HDU 4778 Gems Fight! [博弈+状压DP(记忆化搜索)]

来源:互联网 发布:社区服务网络是什么 编辑:程序博客网 时间:2024/05/16 10:09

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.

题意:

给出B个包裹,每个包裹里有一些不同颜色的宝石,Alice和Bob轮流把一个包裹里的宝石扔到一口锅里,当锅里同一种颜色的宝石数>=S,回得到一颗魔法石,如果某个人的回合内制造了一颗魔法石,他可以进行进行下一轮,问两者采取最优策略时,Alice比Bob多几个魔法石。(可能会一下生成多个魔法石,可能一个人一下子进行好几轮)

范围:

0<=B<=21, 0<=G<=8, 0<n<=10, S < 20. 

解法:

21个包裹,考虑状压DP,一开始考虑的是正向DP,后来发现不太好搞,发现记忆化搜索比较好写,用dfs(int state) 表示当前状态下,先手的能得到的最多魔法石,然后转移的时候需要判断一下先手是否交换即可。

(博弈题的DP大多可以写记忆化搜索,因为正向DP有时候是会错的(大概吧),这道题一开始转移的时候考虑不清,WA了好多发,认为剩下的能得到的魔法石数量只与剩下的包裹有关,其实应该用总的减去前面已经得到的石头数,因为前面会剩下一些宝石……)

代码:

#include<stdio.h>#include<string.h>#include<algorithm>#include<math.h>#include<iostream>#include<stdlib.h>#include<set>#include<map>#include<queue>#include<vector>#include<bitset>#pragma comment(linker, "/STACK:1024000000,1024000000")template <class T>bool scanff(T &ret){ //Faster Input    char c; int sgn; T bit=0.1;    if(c=getchar(),c==EOF) return 0;    while(c!='-'&&c!='.'&&(c<'0'||c>'9')) c=getchar();    sgn=(c=='-')?-1:1;    ret=(c=='-')?0:(c-'0');    while(c=getchar(),c>='0'&&c<='9') ret=ret*10+(c-'0');    if(c==' '||c=='\n'){ ret*=sgn; return 1; }    while(c=getchar(),c>='0'&&c<='9') ret+=(c-'0')*bit,bit/=10;    ret*=sgn;    return 1;}#define inf 1073741823#define llinf 4611686018427387903LL#define PI acos(-1.0)#define lth (th<<1)#define rth (th<<1|1)#define rep(i,a,b) for(int i=int(a);i<=int(b);i++)#define drep(i,a,b) for(int i=int(a);i>=int(b);i--)#define gson(i,root) for(int i=ptx[root];~i;i=ed[i].next)#define tdata int testnum;scanff(testnum);for(int cas=1;cas<=testnum;cas++)#define mem(x,val) memset(x,val,sizeof(x))#define mkp(a,b) make_pair(a,b)#define findx(x) lower_bound(b+1,b+1+bn,x)-b#define pb(x) push_back(x)using namespace std;typedef long long ll;typedef pair<int,int> pii;#define NN 2200000int b,g,s;int c[33][11];int cot[NN][11];int tot[NN];int dp[NN],tst;bool vis[NN];int dfs(int x,int st){    if(vis[st])return dp[st];    int z=1,nst;    vis[st]=1;    dp[st]=0;    rep(i,1,b){        if(~st&z){            nst=st|z;            if(tot[nst]-tot[st]>0){//此人继续                dp[st]=max(dp[st],dfs(x,nst)+tot[nst]-tot[st]);            }            else{ //换人                dp[st]=max(dp[st],tot[tst]-tot[st]-dfs(x^1,nst));            }        }        z<<=1;    }    return dp[st];}int main(){    while(scanf("%d%d%d",&g,&b,&s)!=EOF){        if(b==0&&g==0&&s==0)break;        tst=(1<<b)-1;        mem(c,0);        rep(i,1,b){            int n;            scanff(n);            rep(j,1,n){                int x;                scanff(x);                c[i][x]++;            }        }        int x=1,num=1;        mem(vis,0);        rep(st,1,tst){            tot[st]=0;            if(st>=x*2)x<<=1,num++;            int pst=st-x;            rep(i,1,g){                cot[st][i]=cot[pst][i]+c[num][i];                tot[st]+=cot[st][i]/s;            }        }                int a=dfs(0,0);        int b=tot[tst]-a;        printf("%d\n",a-b);    }    return 0;}


0 0
原创粉丝点击