hdu4778Gems Fight!

Gems Fight!

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


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 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.
 
Source
#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std ;

#define INF 300000000

int dp[(1<<21)+1] ;
int c[22][22] ,s , b , g;
int num[22] , n ;
int max1( int a , int b ){ return a > b ? a : b ;}
int dfs( int cur , int left , int cc[])//当前状态是cur,还有left宝石没有被取,cc里面是上一次取了以后剩下来的
{                                      // 返回的是先手可以取到的最大宝石
    if( cur == 0 || left == 0 ) return 0 ;
    else if( dp[cur] != INF ) return dp[cur] ;
    int i , j , mm , ans = 0 , ret , k , m1 ;
    int dd[22] ;

        for( j = 0 ; j < b ;j++)if(cur&(1<<j)) // 改位为 1 说明没有被取,这次取这位(也就是拿去 第 j 袋)
        {
            mm = cur^(1<<j) ; // 把这位取了,
            ret = 0 ;
            for( k = 1 ; k <= g ;k++)
            {
                dd[k] = cc[k]+c[j][k] ;
                ret += dd[k]/s ;
                while(dd[k] >= s)
                    dd[k] -= s ;
            }           // ret 记录这次取到的宝石
            if(ret)
                m1 = ret+dfs(mm,left-ret,dd) ; //如果可以取,说明下次还是当前的人取,可以取的宝石数 - ret 
            else m1 = left - dfs(mm,left,dd) ; //如果不可以,说明先手下次换人,当前先手可以取到的最大值就是 left-下一个先手可以取到的最大值了
            ans = max(m1,ans) ;
        }
    return dp[cur] = ans ;//记忆状态
}
int main()
{
    int i , j ;
    int sum , tt , t , ans ;
 //freopen("in.txt","r",stdin) ;
    while( scanf("%d%d%d" , &g , &b , &s) != EOF )
    {
        if(s+g+b == 0 )break ;
        memset(c,0,sizeof(c)) ;
        memset(num,0,sizeof(num)) ;
        sum = 0 ;
        for( i = 0 ; i < b ;i++ )
        {
            scanf("%d" , &n ) ;
            while(n--)
            {
                scanf("%d" , &t) ;
                c[i][t]++ ;
                num[t]++ ;
            }
        }
        n = (1<<b) ;
        for( i = 0 ; i <= n ;i++)
            dp[i] = INF ;
        for( i = 1 ; i <= g ;i++ )
          sum += num[i]/s ;
          memset(num,0,sizeof(num)) ;
        ans = dfs(n-1,sum,num) ;
        // ans 是先手取到的最大, 后手就是 sum-ans ,所以答案是 ans-(sum-ans);
        printf("%d
",2*ans-sum) ;
    }
    return 0 ;
}
原文地址:https://www.cnblogs.com/20120125llcai/p/3438087.html