题目链接 HDU3182
【题意】
有n个汉堡,某个人当前有E能量值,吃掉每个汉堡需要花费ei能量,可以获得vi价值,并且吃掉当前汉堡之前必须先制作Q[ ]汉堡,每个Qi输入最后几行给出了,每个汉堡只能被吃掉一次。求出改人能获得的最大的能量值。
【分析】
有点类似背包,其实不需要背包,超级简单,只要用dp[s]表示当前已经吃掉的的汉堡集合s(状压表示)最多还能获得多少价值,直接记忆化搜一下就行了,达不到要求的不会被搜索到。最后dp[0]就是所求的最大值,具体看代码。
【AC代码】0ms
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define MAXN 15
struct NODE{
int len, s[MAXN];
}p[MAXN];
int n, m, v[MAXN], w[MAXN], dp[1<<MAXN];
//dp[s]表示当前已经吃掉的汉堡集合s还能获得的最大价值
bool ok(int s, int i)//判断现在已经吃掉的汉堡能否满足吃掉汉堡i
{
for (int j = 0; j < p[i].len; j++)
{
if (0 == (s&(1 << p[i].s[j])))
return false;
}
return true;
}
int dfs(int s, int c)
{
if (-1 != dp[s]) return dp[s];
dp[s] = 0;
for (int i = 0; i < n; i++)
{
if (s&(1 << i)) continue;//已经吃掉的汉堡不能再做了
if (0 <= c - w[i] && ok(s, i))//找到下一个吃掉哪种汉堡能获得的价值最大
dp[s] = max(dp[s], dfs(s|(1<<i),c-w[i])+v[i]);
}
return dp[s];
}
int main()
{
#ifdef SHY
freopen("e:\\1.txt", "r", stdin);
#endif
int t;
scanf("%d%*c", &t);
while (t--)
{
int a;
scanf("%d %d%*c", &n, &m);
for (int i = 0; i < n; i++)
p[i].len = 0;
memset(dp,-1,sizeof(dp));
for (int i = 0; i < n; i++)
scanf("%d%*c", &v[i]);
for (int i = 0; i < n; i++)
scanf("%d%*c", &w[i]);
for (int i = 0; i < n; i++)
{
scanf("%d%*c", &p[i].len);
for (int j = 0; j < p[i].len; j++)
{
scanf("%d%*c", &a);
p[i].s[j] = a-1;
}
}
printf("%d\n", dfs(0, m));
}
return 0;
}