hdu 4778 Gems Fight!(2013acmicpc亞洲區域賽杭州站 I)


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;
}





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章