hdu 4778 Gems Fight!(2013acmicpc亚洲区域赛杭州站 I)

13 篇文章 0 订阅
3 篇文章 0 订阅


http://acm.hdu.edu.cn/showproblem.php?pid=4778


Gems Fight!

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


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.


题目大意:有B个盒子里面放有G种颜色的宝石,两个人轮流选一个盒子将其中的宝石取出来放到一个锅里,然后其中没有S个相同颜色的宝石,它们就会聚合在一起变成一个魔法石(可能产生多个魔法石且锅里有可能有剩余的宝石),然后本轮的得分就是产生的魔法石的数量,且如果本轮某个人拿到了魔法石的话,那么下一轮他还可以继续选择盒子放入宝石,知道他在某一轮没有拿到魔法石,现在问两个人都采用最优策略的情况下,到最后先拿的那个人的得分与后拿的人的得分的差是多少。

思路:通过题意我们可以发现,所获得的的魔法石是一定的,也就是说不管按照什么顺序选择,到最后两人拿到的魔法石之和是一定的(这很容易算出来),然后可以发现B最多只有21个,那么我们可以通过状压来表示在某一个状态下先手最多可以拿多少个魔法石。我们可以通过记忆化搜索来解决这个问题,首先在某个特定的状态下,锅里所剩余的宝石是固定的,且还能拿到的魔法石的数量也是一定的。那么我们设dp[flag]表示状态是flag下先手最多可拿的魔法石数量,接下来就是状态转移了。

假设我们选择了第i个盒子((flag>>i)&1==1),则我们可以算可拿到多少个魔法石,设为x个,如果x>0,表示下一轮还是自己选,

则dp[flag]=max(dp[flag],dp[flag^(1<<i)]+x),

否则下一轮是对方选择,

则 dp[flag]=max(dp[flag],left-dp[flag^(1<<i)]),这里的left表示当前状态下还可以拿多少个魔法石。

最后我们求dp[(1<<b)-1]即可。最后还要注意我们要求的答案是两者得分之差,注意转换一下即可。

代码如下:

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define inf -2100000000
using namespace std;
int dp[1<<21];
int g,b,s;
int box[21][8],c[8];
int dfs(int flag,int left,int cc[])
{
    if(left==0||flag==0)
    return 0;
    if(dp[flag]!=inf)
    return dp[flag];
    int i,tmp,ans=0,ben;
    int tt[8];
    memset(tt,0,sizeof(tt));
    for(i=b-1;i>=0;i--)
    {
        ben=0;
        if((flag>>i)&1)
        {
            tmp=flag^(1<<i);
            int sum=0;
            for(int j=0;j<g;j++)
            {
                tt[j]=(cc[j]+box[i][j]);
                sum+=tt[j]/s;
                tt[j]%=s;
            }
            if(sum)
            {
                ben=sum+dfs(tmp,left-sum,tt);
            }
            else
            {
                ben=left-dfs(tmp,left,tt);
            }
            ans=max(ans,ben);
        }
    }
    return dp[flag]=ans;
}
int main()
{
   // freopen("dd.txt","r",stdin);
    while(scanf("%d%d%d",&g,&b,&s))
    {
        if(!g)
        break;
        memset(box,0,sizeof(box));
        memset(c,0,sizeof(c));
        for(int i=0;i<b;i++)
        {
            int n,x;
            scanf("%d",&n);
            while(n--)
            {
                scanf("%d",&x);
                box[i][x-1]++;
                c[x-1]++;
            }
        }
        int sum=0;
        for(int i=0;i<g;i++)
        {
            sum+=c[i]/s;
        }
        int cc[8];
        int limit=(1<<b);
        for(int i=0;i<limit;i++)
        {
            dp[i]=dp[i]=inf;
        }
        memset(cc,0,sizeof(cc));
        int ans=dfs((1<<b)-1,sum,cc);
        printf("%d\n",2*ans-sum);
    }
    return 0;
}





  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值