hdu 4778 Gems Fight! ( 状压dp+记忆化搜索 )

81 篇文章 1 订阅

Gems Fight!

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


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 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.
 

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


题意:
有B个包裹,里面有各种颜色的GEM,共有G个颜色。Alice和Bob轮流挑选包裹放到一个地方,如果挑选出来的同种颜色的GEM超过S个,当前回合者可以得分,每超过S个得一分。如果在回合内得分了,可以额外进行一个回合。问Alice的得分减去Bob的得分最大是多少。

思路:
只有21个bag,可以考虑状压,每一位表示每个bag的拿的情况,然后就是记忆化搜索实现博弈了,Alice和Bob性质都是一样的,可以一起处理。另外就是系数控制好,不然会TLE,看清得分的本质在哪里,预处理一下每个状态的能得的分数就够了,然后状态转移时看两个状态的得分数有没改变。

代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<ctime>
#include<map>
#include<cmath>
#include<set>
#include<stack>
#include<algorithm>
#define maxn 1005
#define MAXN 1000005
#define eps 1e-6
#define INF 0x3f3f3f3f
using namespace std;

int n,m,ans,sum,en;
int b,g,s;
int ball[25][10],num[10],tmp[10];
int dp[1<<22],bs[1<<22];

void presolve()
{
    int i,j,k,t;
    memset(tmp,0,sizeof(tmp));
    for(i=0;i<=en;i++)
    {
        t=0;
        for(j=0;j<b;j++)
        {
            if(i&(1<<j))
            {
                for(k=1;k<=g;k++)
                {
                    tmp[k]+=ball[j][k];
                }
            }
        }
        for(j=1;j<=g;j++)
        {
            t+=tmp[j]/s;
            tmp[j]=0;
        }
        bs[i]=t;
    }
}
int dfs(int val,int ssum)
{
    if(dp[val]!=-1) return dp[val];
    int i,j,best=0,s,st;
    for(i=0;i<b;i++)
    {
        if(val&(1<<i)) continue ;
        st=val|(1<<i);
        s=bs[st]-bs[val];
        if(s) best=max(best,dfs(st,ssum-s)+s);
        else best=max(best,ssum-dfs(st,ssum));
    }
    dp[val]=best;
    return best;
}
int main()
{
    int i,j,t;
    while(scanf("%d%d%d",&g,&b,&s),b||g||s)
    {
        memset(ball,0,sizeof(ball));
        memset(num,0,sizeof(num));
        for(i=0;i<b;i++)
        {
            scanf("%d",&n);
            for(j=1;j<=n;j++)
            {
                scanf("%d",&t);
                ball[i][t]++;
                num[t]++;
            }
        }
        sum=0;
        for(i=1;i<=g;i++)
        {
            sum+=num[i]/s;
        }
        en=(1<<b)-1;
        presolve();
        memset(dp,-1,sizeof(dp));
        dp[en]=0;
        ans=dfs(0,sum);
        printf("%d\n",ans-(sum-ans));
    }
    return 0;
}






 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值