HDU 4778 Gems Fight!_状压

来源:互联网 发布:数组是线性表吗 编辑:程序博客网 时间:2024/06/06 12:54

原题:

Gems Fight!

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


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.
 



题意+题解:

一道博弈类的状压题

题意我记不大清了。。。大概是G种颜色,B个包裹,包裹里有一些Gems,这个会给出来,然后两个人轮流取一个包裹,把里面的Gems放到一个锅里,如果此时里面的某一种颜色的Gems的和大于S的话(S是题目中给出的一个定值),那么此人获得一个魔法石,并有权利再选择一个包裹继续自己的回合,直到没有取到魔法石时,回合交给对方。两个人都是最优决策,求先手的魔法石与后手的差值

。。。只是翻译了一下,没有想到更精炼的语言去描述它。

这里G的种类有8种,包裹有21个,一共最多也就200个Gems。可以用状态压缩表示包裹的选取状态,并计算当前状态下先手取包裹的最优值。

定义状态:  dp[1<<21];表示选取状态为i时(0表示之前已经选过了,1表示剩下的可选包裹),先手取包裹的能获得的最大值。(差值可以有最大值*2-总魔法石得到)

转移:

对于一个状态 u 此时选了的包裹和未选的包裹都确定,这是锅里面的剩余的各种颜色的GEM的个数也确定,由于总的魔法时的数量是可以在一开始就计算出来,所以当在状态u的时候剩下的可选的包裹能组成的魔法石的数量也确定,用变量left记录当前剩余的包裹中可以组成的魔法石数量


递归时 dfs(u,left)表是在包裹状态为u时,剩余魔法石数量为left时,以先手取包裹所能得到的最大值作为函数的返回值

在dfs(u.left)中,取剩下的每一个包裹尝试一次,然后计算取此次包裹后所能得到的魔法石数量,记为temp_stone;

开辟一个辅助数组,记录当取状态为u的时候,锅里面剩余的各种颜色的GEMs的个数,remain[u][]


当temp_stone>0的时候,表示先手可以继续自己的回合,;故继续深层dfs,此时

dp[u]=max ( dp[u]  ,   temp_stone + dfs(temp_status,,left - temp_stone ) );


当temp_stone==0时,表示没有得到魔法石,此时回合交给对方,那么对方下次的dp值就是他先手的时候的最大值,这样u状态下的dp值就是 left-dp[下次]

dp[u]=max( dp[u] ,left - dfs(temp_status,left));

最后就是dp[(1<<bags)-1]即为先手最大值

代码:

#include<cstdio>#include<cstring>#include<vector>#include<queue>#include<cmath>#include<iostream>#include<algorithm>#include<functional>#define INF -99999999using namespace std;int num_color,num_bag,s;int bags[25][10];int dp[1<<21];bool vis[1<<21];int color[10];int remain_color[1<<21][10];//表示第i种状态下,锅里各种颜色的Gems的个数int dfs(int u,int left)//状态u下的 dp值,left表示在u状态下,未取的这些包中所含有的魔法石总量{if(left==0)return 0;if(vis[u])return dp[u];vis[u]=1;int i,j,temp_status,temp_stone;for ( i = 0; i < num_bag; i++)//尝试去取每个包裹,从中选取一个最优的作为方案{if(u&(1<<i))//原状态下第i个包未取,取之{temp_stone=0;temp_status = u &(~(1<<i));for ( j = 1; j <= num_color; j++){remain_color[temp_status][j]=remain_color[u][j]+bags[i][j];temp_stone+=remain_color[temp_status][j]/s;remain_color[temp_status][j]%=s;}if (temp_stone)//表示取了第i个包后得到魔法石,故还可以再来一回合{dp[u]=max(dp[u],temp_stone+dfs(temp_status,left-temp_stone));}else//表示未去到,故先后手反转{dp[u]=max(dp[u],left-dfs(temp_status,left));}}}return dp[u];}int main(){int  i,temp,total_stone,n,limit;while (scanf("%d%d%d",&num_color,&num_bag,&s),num_color || num_bag || s){limit=(1<<num_bag)-1;total_stone=0;memset(color,0,sizeof(color));memset(bags,0,sizeof(bags));memset(vis,0,sizeof(vis));for ( i = 0; i < num_bag; i++){scanf("%d",&n);while (n--){scanf("%d",&temp);bags[i][temp]++;color[temp]++;}}for(i=1;i<=limit;i++)dp[i]=INF;for ( i = 1; i <= num_color; i++){total_stone+=color[i]/s;remain_color[limit][i]=0;}printf("%d\n",2*dfs(limit,total_stone)-total_stone);}return 0;}



0 0
原创粉丝点击