题目描述:
题意:有N个汉堡,你有一定的能量值E,每个汉堡有自己的价值v,并且制作需要花费一定的能量值e,但是有些汉堡制作需要先制作一些特定的汉堡才行,求怎样制作汉堡能够获得的最大的价值。
这题其实不难,但是我坑在了一个十分愚蠢的地方,很气,于是要写下这道题。首先状态是十分好设计,汉堡最多只有15个,那么直接采取状态压缩,dp[i][j]表示i状态下使用了j能量时获得的价值。直接枚举所有状态,加进汉堡时在检验一下是否能加,能加的话更新状态和答案。这题唯一的坑点在于在枚举状态时,存在某些状态本身不可行的情况。这个问题其实也非常好解决,先把所有状态的初值设为-1,dp[0][0]设为0,因为该状态必然可行,并且所有状态肯定是从该状态转移得来的,所以自然从dp[0][0]开始进行状态转移,那么所有可行的状态都会被赋值,所以对后面状态枚举时只需检验他是否为-1即可。这个方法其实我很快就想到了,但是我坑在了一个极为愚蠢的地方,我把ans初始化成了-1,但是存在所有状态都不可行的情况,这个时候无法转移,答案就是0,我居然想了那么久都没想到!!!
AC代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<stack>
#include<vector>
#include<queue>
#include<algorithm>
using namespace std;
const int INF=0x3f3f3f3f;
const int MAXM=25;
int N,E;
int n[20];
int e[20];
int dp[1<<16][110];
vector<int > need[20];
int cal(int x)
{
int hav=0;
for (int i=1;i<=N;i++)
{
if (x&(1<<(i-1)))
hav=hav+e[i];
}
return hav;
}
bool check(int state,int x)
{
for (int i=0;i<(int)need[x].size();i++)
if (!(state&(1<<(need[x][i]-1)))) return false;
return true;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&N,&E);
for (int i=1;i<=N;i++)
scanf("%d",&n[i]);
for (int i=1;i<=N;i++)
scanf("%d",&e[i]);
int q;
for (int i=0;i<20;i++)
need[i].clear();
for (int i=1;i<=N;i++)
{
scanf("%d",&q);
int x;
while(q--)
{
scanf("%d",&x);
need[i].push_back(x);
}
}
memset(dp,-1,sizeof(dp));
dp[0][0]=0;
int ans=0;//愚蠢的我被这里坑了。。。QAQ。
for (int i=0;i<(1<<N);i++)
{
int hav=cal(i);
if (dp[i][hav]!=-1)
{
for (int j=1;j<=N;j++)
{
if (hav+e[j]>E) continue;
if (i&(1<<(j-1))) continue;
if (check(i,j))
{
int state=i|(1<<(j-1));
dp[state][hav+e[j]]=dp[i][hav]+n[j];
ans=max(ans,dp[state][hav+e[j]]);
}
}
}
}
printf("%d\n",ans);
}
return 0;
}