hdu 4778 Gems Fight!(状态压缩dp)

题目链接

Gems Fight!

Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 327680/327680 K (Java/Others)
Total Submission(s): 998    Accepted Submission(s): 414


Problem Description
  Alice and Bob are playing "Gems Fight!":
  There are Gems of G different colors , packed in B bags. Each bag has several Gems. G different colors are numbered from color 1 to color G.
  Alice and Bob take turns to pick one bag and collect all the Gems inside. A bag cannot be picked twice. The Gems collected are stored in a shared cooker.
  After a player ,we name it as X, put Gems into the cooker, if there are S Gems which are the same color in the cooker, they will be melted into one Magic Stone. This reaction will go on and more than one Magic Stone may be produced, until no S Gems of the same color remained in that cooker. Then X owns those new Magic Stones. When X gets one or more new Magic Stones, he/she will also get a bonus turn. If X gets Magic Stone in a bonus turn, he will get another bonus turn. In short,a player may get multiple bonus turns continuously.
  There will be B turns in total. The goal of "Gems Fight!" is to get as more Magic Stones than the opponent as possible.
  Now Alice gets the first turn, and she wants to know, if both of them act the optimal way, what will be the difference between the number of her Magic Stones and the number of Bob's Magic Stones at the end of the game.
 

Input
  There are several cases(<=20).
  In each case, there are three integers at the first line: G, B, and S. Their meanings are mentioned above.
  Then B lines follow. Each line describes a bag in the following format:
  
  n c 1 c 2 ... c n
  
  It means that there are n Gems in the bag and their colors are color c 1,color c 2...and color c n respectively.
   0<=B<=21, 0<=G<=8, 0<n<=10, S < 20.
  There may be extra blank lines between cases. You can get more information from the sample input.
  The input ends with G = 0, B = 0 and S = 0.
 

Output
  One line for each case: the amount of Alice's Magic stones minus the amount of Bob's Magic Stones.
 

Sample Input
   
   
   
   
3 4 3 2 2 3 2 1 3 2 1 2 3 2 3 1 3 2 2 3 2 3 1 3 1 2 3 0 0 0
 

Sample Output
   
   
   
   
3 -3
Hint
  For the first case, in turn 2, bob has to choose at least one bag, so that Alice will make a Magic Stone at the end of turn 3, thus get turn 4 and get all the three Magic Stones.
题意:G种颜色的宝石,B个包,每个包里装了一些有颜色的宝石,还给了个s。两个人做游戏,一个人一回合可以拿一个包,将包里的宝石放在桌子上,这个人可以将S个颜色相同的宝石合成一个魔法石,每回合可以合成多个魔法石,一个宝石和一个包只能被用一次。假设这个人合成了>0个宝石,那么下个回合还是这个,不然就是另一个人。两人都采用最优策略,问先手合成的魔法石的数量和后手合成的魔法石的数量之差。G<=8,B<=21。每个包最多10个宝石。

题解:刚读完题感觉有点繁琐。由于G和B都很小,所以可以考虑状压dp。首先容易想到一个比较暴力的状态dp【0,1】【i】【s1】【s2】,表示某个人第i回合桌子上的状态为s1,剩下的包的状态为s2能得到的最大价值。但是这样明显空间和时间都不能承受。仔细分析,如果我们已知包的状态,可以计算出桌子上的状态。所以s1这一维可以省掉。然后,表示第i回合这一维也是可以省掉的,我们只关心能得到的最大价值,完全不用记录这是第几回合。这样状态看起来可以接受了,但是仔细算算,加上转移,复杂度是10^8的数量级,还是有可能超时。仔细分析我们求的是差值,其实不用求最值,我们用dp【s】表示,当前这个人,面对包的状态是S,他和另一个人的最大差值是多少。那么转移就很显然了。具体见代码:

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<vector>
#include<math.h>
#include<stack>
#include<map>
#include<queue>
#include<set>
#define nn 2200000
#define inff 0x3fffffff
using namespace std;
typedef long long LL;
int g,b,S;
int bao[30][20];
int dp[nn];
int cl[nn][10];
int main()
{
    int i,j,k;
    int x,y;
    while(scanf("%d%d%d",&g,&b,&S)&&g+b+S)
    {
        memset(bao,0,sizeof(bao));
        for(i=0;i<b;i++)
        {
            scanf("%d",&x);
            for(j=0;j<x;j++)
            {
                scanf("%d",&y);
                bao[i][y]++;
            }
        }
        dp[0]=0;
        memset(cl,0,sizeof(cl));
        int ix;
        for(i=1;i<(1<<b);i++)
        {
            dp[i]=-inff;
            for(j=0;j<b;j++)
            {
                if((1<<j)&i)
                    continue;
                for(k=1;k<=g;k++)
                {
                    cl[i][k]+=bao[j][k];
                }
            }
            for(k=1;k<=g;k++)
                cl[i][k]%=S;
            for(j=0;j<b;j++)
            {
                if((1<<j)&i)
                {
                    ix=0;
                    for(k=1;k<=g;k++)
                    {
                        ix+=(cl[i][k]+bao[j][k])/S;
                    }
                    if(ix>0)//如果拿第j个包能合成出大于0个魔法石,那么下回合还是这个人
                        dp[i]=max(dp[i],ix+dp[i^(1<<j)]);
                    else//反之,下回合是另一个人
                        dp[i]=max(dp[i],-dp[i^(1<<j)]);
                }
            }
        }
        printf("%d\n",dp[(1<<b)-1]);
    }
    return 0;
}


你可能感兴趣的:(dp,动态规划,ACM)