您的位置:首页 > 其它

Hdu 4778 Gems Fight! (状态压缩 + DP)

2015-10-27 16:47 489 查看
题目链接:

  Hdu 4778 Gems Fight!

题目描述:

  就是有G种颜色,B个背包,每个背包有n个宝石,颜色分别为c1,c2...........。两个人轮流取背包放到公共容器里面,容器里面有s个相同颜色宝石的时候,这s个相同颜色的宝石会融合成一个魔法石。当选手选择一个背包放到公共容器里会产生魔法石,魔法石就归这个选手所有,并且奖励这个选手再选一个背包,直到不再产生魔法石为止。(每个背包只能选取一次)每个选手会尽量使自己得到的魔法石最多,问最后先手减后手的值?

解题思路:

  数据范围比较小,很容易想到状态压缩。然后就是状态压缩的姿势了。考虑到最后产生的魔法石数目是一定的,只不过是选择的策略不同先手和后手拿到的魔法石数目会不同。所以我们可以枚举第一个选中的背包。dp[i] 表示 状态i的最优解(先手-后手得分的最大值)。枚举第j个背包是最后加入的,如果第j个加入不能产生魔法石,那么就要 - dp[i^(1<<j)],因为加入不能产生魔法石,以前的第一个背包要让给后手选,那么第j个背包加入会产生魔法石,那么就 + dp[1^(1<<j)],这样原来第一个背包还是作为奖励让前手选。

#include<stdio.h>
#include <queue>
#include<string.h>
#include<math.h>
#include<stdlib.h>
#include<algorithm>
using namespace std;

typedef long long LL;
const int maxn = 22;
const int INF = 0x3f3f3f3f;
int dp[1<<maxn], c[maxn][10], a[maxn], b[maxn];

int main ()
{
int G, B, S;
while (scanf ("%d %d %d", &G, &B, &S), G + B + S)
{
int num, x;
memset (c, 0, sizeof(c));
for (int i=0; i<B; i++)
{
scanf ("%d", &num);
for (int j=0; j<num; j++)
{
scanf ("%d", &x);
c[i][x] ++;
}
}

dp[0] = 0;
int n = 1 << B;
for (int i=1; i<n; i++)
{
dp[i] = -INF;
memset (a, 0, sizeof(a));
for (int j=0; j<B; j++)
{
if ((i & (1<<j)) == 0)
{
for (int k=1; k<=G; k++)
a[k] += c[j][k];
}
}

for (int j=0; j<B; j++)
a[j] %= S;

for (int j=0; j<B; j++)
{
if ((i & (1<<j)))
{
int nu = 0;
for (int k=1; k<=G; k++)
nu += (a[k] + c[j][k]) / S;

if (nu)
dp[i] = max (dp[i], nu + dp[i^(1<<j)]);
else
dp[i] = max (dp[i], nu - dp[i^(1<<j)]);
}
}
}
printf ("%d\n", dp[n-1]);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: