HDU 4778 Gems Fight! 状态压缩dp

来源:互联网 发布:php usleep 100毫秒 编辑:程序博客网 时间:2024/06/08 07:36

Gems Fight!

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


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 c1 c2 ... cn
  
  It means that there are n Gems in the bag and their colors are color c1,color c2...and color cn 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 32 2 32 1 32 1 23 2 3 13 2 23 2 3 13 1 2 30 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.

Source
2013 Asia Hangzhou Regional Contest 

题意:一共G种不同颜色的宝石,有B个袋子,每个袋子里面有一些珍珠,然后Alice和Bob要轮流取一个袋子,把所有的珍珠拿出来放到一个公共的地方,如果公共地方里面目前有相同颜色的宝石有S个,这个S个会被融成一个“石头”,如果一个人取了一个袋子后导致有一个或多个宝石融成石头,这些石头就是属于他的,并且他要继续取袋子,问如果两个人的目标是属于自己的石头尽可能比对方多。问如果两个人按最优策略走,最后两个人的石头的差值是多少。


思路:首先发现袋子最多21个,我们想想能不能进行状态压缩?是可以的,我们考虑一下假设我们知道了哪些袋子已经被取过了,那么能否直接得出现在各个宝石的情况能,是可以的,就是对应颜色的宝石加起来%S就可以了,那么我们在考虑现在要多拿一个袋子,于是把新的宝石情况统计一下,看能得出多少的石头,进行相应的转移。石头为0,就是转移到下一个对手,否则就还是自己。 所以我们直接用状态压缩dp来推就行了,但是我们要从“叶子”开始往前推,具体可以直接看代码。


代码:

#include <iostream>#include <cstdio>#include <cstring>#include <cassert>#include <queue>#include <vector>#include <map>#include <set>#include <cmath>#include <algorithm>using namespace std;#define rep(i,a,b) for(int i=(a);i<(int)(b);++i)#define rrep(i,b,a) for(int i=(b);i>=(int)(a);--i)#define eps 1e-8#define clr(a,x) memset(a,x,sizeof(a))#define mp make_pair#define LL long longconst int maxn = 20 + 5;const int inf = 1e8;int G, B, S;int color[22][10];void input(){    clr(color,0);    rep(i,0,B) {        int sz;        scanf("%d",&sz);        rep(j,0,sz) {            int x; scanf("%d",&x); --x;            color[i][x]++;        }    }}int dp[(1<<21)][2];inline int max(int a,int b) { return a > b ? a : b; }inline int min(int a,int b) { return a < b ? a : b; }int sum[10];void solve(){    int mask = (1<<B)-1;    rep(i,0,mask+1) dp[i][0] = -inf, dp[i][1] = inf;    dp[mask][0] = dp[mask][1] = 0;    rrep(s,mask-1,0) {        clr(sum,0);        rep(i,0,B) if (s&(1<<i)) {            rep(j,0,G) sum[j] += color[i][j];        }        rep(j,0,G) sum[j] %= S;        rep(i,0,B) if (!(s&(1<<i))) {            int t = s | (1<<i);            rep(j,0,G) sum[j] += color[i][j];            int stone = 0;            rep(j,0,G) stone += sum[j] / S;            dp[s][0] = max(dp[t][stone == 0] + stone,dp[s][0]);            dp[s][1] = min(dp[t][stone != 0] - stone,dp[s][1]);            rep(j,0,G) sum[j] -= color[i][j];        }    }    printf("%d\n",dp[0][0]);}int main(){    while (scanf("%d%d%d",&G,&B,&S),G+B+S) {        input();        solve();    }}



0 0