http://acm.hdu.edu.cn/showproblem.php?pid=3182
建议先做hdu 1074题。
同1074题思路差不多,但这里加了条件判断,即判断做第k个汉堡是是否做出了它的所有先决汉堡,对于每个先决汉堡,也要进行相同的判定。这显然有点难度。
优化的一个思路是在初始化时将所有dp.value初始化为负无限大,只有dp[0].value=0。此时,对于任意一种情况,只要没有先决条件为0的子情况,其value无限小。
最后遍历一边数组,找出其最大value即可。
博主在这里提供另一种思路:i表示某种可能发生的情况,对于所有未完成的汉堡k,判断其先决汉堡是否在i这种情况中完成了,完成,即更新dp[i+k].value。否则dp[i+k].value为无限小。
#include<iostream>
#include<cstdio>
using namespace std;
const int N=15;
#define max(a,b) a>b?a:b;
struct DPT{
int value;
int energy;//到此种情况剩余的能量
DPT()
{
energy=0;
}
}dp[(1<<N)+5];
int a[N];
int b[N];
int c[N][N]; //储存某种汉堡的先决汉堡的二进制值
int main()
{
int t;
cin>>t;
while(t--)
{
memset(c,0,sizeof(c));
int n,m;
cin>>n>>m;
for(int i=0;i<n;i++)
cin>>a[i];
for(int i=0;i<n;i++)
cin>>b[i];
for(int i=0;i<n;i++)
{
cin>>c[i][0];
for(int j=1;j<=c[i][0];j++)
{
int bb;
cin>>bb;
c[i][j]=(1<<(bb-1));
}
}
int end=1<<n;
for(int i=1;i<end;i++)
dp[i].value=-100000;
dp[0].value=0;
dp[0].energy=m;
for(int i=1;i<end;i++)
{
bool judge=false;
for(int j=n-1;j>=0;j--)
{
judge=false;
int k=1<<j;
if(k&i)
{
int tmp=i-k;
//如果上一种情况剩余的能量大于等于制作第j份汉堡的能量,且第j份汉堡的先决汉堡应该已经完成
if(dp[tmp].energy<b[j])
continue;
for(int kk=1;kk<=c[j][0];kk++)
if(!(tmp&c[j][kk]))
{
judge=true;
break;
}
if(judge) continue;
if(dp[i].value<dp[tmp].value+a[j])
{
dp[i].value=dp[tmp].value+a[j];
dp[i].energy=dp[tmp].energy-b[j];
}
else if(dp[i].value==dp[tmp].value+a[j]&&dp[i].energy<dp[tmp].energy-b[j])
{
dp[i].energy<dp[tmp].energy-b[j];
}
}
}
}
int maxn=0;
for(int i=end-1;i>0;i--)
maxn=max(dp[i].value,maxn);
cout<<maxn<<endl;
}
return 0;
}