HDU 4778 Gems Fight! 【记忆化搜索+位操作】

来源:互联网 发布:dracut命令安装linux 编辑:程序博客网 时间:2024/06/05 20:50


Gems Fight!

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

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. Gdifferent 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 bagcannot 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 whichare 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, untilno S Gems of the same color remained in that cooker. Then X owns those newMagic Stones. When X gets one or more new Magic Stones, he/she will also get abonus turn. If X gets Magic Stone in a bonus turn, he will get another bonusturn. 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 moreMagic Stones than the opponent as possible.
  Now Alice gets the first turn, and she wants to know, if
both of them act theoptimal way, what will be the difference between the number of her MagicStones 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. Theirmeanings are mentioned above.
  Then B lines follow. Each line describes a bag in the following format:
  
  n c
1c2 ... cn
  
  It means that there are n Gems in the bag and their colors are color c
1,colorc2...and color cn respectively.
  0<=B<=21, 0<=G<=8, 0<n<=10, S < 20.
  Theremay be extra blank lines between cases. You can get more information from thesample input.
  Theinput 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 ofBob'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 Alicewill make a Magic Stone at the end of turn 3, thus get turn 4 and get all thethree Magic Stones.

 


【题意】


现在有B个背包,每个背包里有各种颜色的物品若干。总共有G种颜色。现在Alice和Bob轮流选择一个包裹并将其中的物品放到一个混合器中。如果混合器中某种颜色的物品超过了S件,那么每S件会融合出一个宝石,并获得额外一次选择背包的权利。问如果两个人足够聪明,且Alice先手,Alice获得的宝石减去Bob获得的宝石是多少。


【思路】


由于数据范围较小,可以考虑暴力DFS,但为了提高效率,用上记忆化搜索。


具体做法见代码注释。


#include <cstdio>#include <vector>#include <cstring>#include <algorithm>using namespace std;#define mst(a,b) memset((a),(b),sizeof(a))#define rush() int T;scanf("%d",&T);while(T--)typedef long long ll;const int maxn = 205;const ll mod = 1e9+7;const int INF = 0x3f3f3f3f;const double eps = 1e-9;int g,b,s;int n;int num[maxn];         //混合器中每种颜色物品的数目 int dp[1<<22];         //dp[i]表示在状态为i时Alice能比Bob多拿的宝石数struct node{    int c[10];         //某个背包里某种颜色物品的数量}bag[22];void init(){    int k=(1<<b);    mst(dp,-1);    dp[k-1]=0;        //所有背包都被使用过的最终状态    mst(num,0);    mst(bag,0);}int solve(int k)                //得到的宝石数{    int ans=0;    for(int i=1;i<=g;i++)    {        num[i]+=bag[k].c[i];        while(num[i]>=s)        {            ans+=num[i]/s;            num[i]%=s;        }    }    return ans;}int dfs(int now){    if(dp[now]!=-1) return dp[now];    int temp[10];    int ans=-INF;    for(int i=1;i<=g;i++)    {        temp[i]=num[i];    }    for(int i=0;i<b;i++)    {        int k=(1<<i);        if(!(now&k))                 //这个背包没被用过        {            int total=solve(i);            if(total>0)     ans=max(ans,total+dfs(now|k));   //下一轮还是这个人,故加上            else            ans=max(ans,total-dfs(now|k));   //下一轮换了一个人,故减去            for(int j=1;j<=g;j++)              //回溯,恢复原来的num值            {                num[j]=temp[j];            }        }    }    return dp[now]=ans;}int main(){    int x;    while(~scanf("%d%d%d",&g,&b,&s)&&(s||b||g))    {        init();        for(int i=0;i<b;i++)        {            scanf("%d",&n);            while(n--)            {                scanf("%d",&x);                bag[i].c[x]++;            }        }        printf("%d\n",dfs(0));    }    return 0;}








原创粉丝点击