其实拿到这道题很容易就能想到是状压dp,原因很简单,因为他每一次打开一个洞穴以后就必须要拿走里面所有的元素(那个伤害什么老大爷就是纯属扯淡),就类似与一个打包子集的概念,而题目要求必须得到所有的元素,再加上元素总共也不多就15个,联想一下最经常做的状压dp的数据范围很容易就想到了
但是今天把枚举子集忘了,还翻了一下大白90页的黑客那道题才记起来:
对于一个全集 S0,他的子集S就是不断地用 (S-1)&S0 来更新,知道最后为0.
原理:
S0&(S - 1)
实际上是把S中的0全部忽略,并不断减1的结果。
例如一个二进制(只是例如没有实际验证计算数字的正确性,懂那个意思就好了)
1000101 不断更新就会是1000100 1000001 1000000.... 1不断减少
#include
#include
#include
#define ll long long
using namespace std;
ll pos[1500000];
int main(){
ll x,n,y,z;
for(int i=1;i<=1e6;i++)pos[i]=1e17+7;
for(ll i=1;i<=15;i++){
scanf("%lld",&x);
pos[1<<(i-1)]=x;
}
scanf("%lld",&n);
for(ll i=1;i<=n;i++){
scanf("%lld",&x);
y=0;
for(ll i=1;i<=x;i++){
scanf("%lld",&z);
y|=1<<(z-1);
}
scanf("%lld",&x);
if(pos[y]>x)pos[y]=x;
}
for(ll i=1;i<(1<<15);i++){
for(ll j=i;j>0;j=(j-1)&i){
pos[i]=min(pos[i],pos[j]+pos[j^i]);
}
}
printf("%lld",pos[(1<<15)-1]);
return 0;
}