URAL 1326. Bottle Taps 压缩DP
题目大意,程序猿想收集tags,还差几个没收集到,问最少花费是多少才能收集完!
给定n, 接下来n个tags的单价;
给定m,然后m中成套收集的方式,每套规定价格,还有个数,后面跟着标号;都是唯一的,证明,每种只需要一种!
最后在给出需要收集那几个,每个都是唯一的!
因为n是最大20;
注意:
可以重复收集,利用压缩DP去做,所谓压缩DP就是利用二进制数表示一种是否已经收集,收集一个或多个用1表示,没有则用0来表示! 第一个没有收集,第二三个已经收集,就用 110即6来表示收集的状态! 其实就是利用或运算的性质来处理!
其他的细节在下面的代码中已经体现了!
#include<iostream>
#include<cstdio>
using namespace std;
struct node
{
int price,cnt;
}nod[120];
int n,m;
int par[22];
int dp[1<<21];
void DFS(int x,int k,int pri)
{
if(x==n)
{
dp[k]=pri;
return ;
}
DFS(x+1,k,pri);///这件不买
DFS(x+1,k|(1<<x) ,pri+par[x]);///这件买
}
int main()
{
cin>>n;
m=1<<n;
for(int i=0;i<n;++i)cin>>par[i];
DFS(0,0,0);///初始化单件购买的情况,没见选择购买或者不购买!
int k;cin>>k;
for(int i=0;i<k;++i)
{
cin>>nod[i].price;
int t,tmp;cin>>t;
while(t--)
{
cin>>tmp; tmp--;
nod[i].cnt=nod[i].cnt|(1<<tmp);
}
}
int w;cin>>w;
int tar=0;
while(w--)
{
int tmp;cin>>tmp;
tmp--;
tar=tar|(1<<tmp);
}
int ans=1000*100;
for(int i=0;i<m;++i)
{
if((i&tar)==tar) ans=min(ans,dp[i]);///注意这里是且运算,他的兴致是只要tar中每位是1的位置i都满足是1,那就等于tar;就是说该卖的都买了吗
for(int j=0;j<k;++j)
{///想想背包的思想,从小到大可以买多次
dp[i|nod[j].cnt]=min(dp[i|nod[j].cnt],dp[i]+nod[j].price);
}
}
cout<<ans<<endl;
return 0;
}