hdu 4778 Gems Fight!(状压+博弈)

题意:有两个人在玩"Gems Fight!"……有B个包,有G种颜色的宝石,这两个人轮流选择某一个包,把这个包里的宝石放到一个共享的熔炉里,当这个熔炉里某一种颜色的宝石大于等于S,那么就可以产生一个魔法石,这个人得到这个魔法石并且还能得到一个额外的回合,两个人都用最佳策略,问最后两个人能获得的魔法石的差是多少。

思路:看到包不多,只有21个,那么可以考虑状压,用一个二进制数表示已经选择的包,则dp[state]表示在state的状态下,先手所能获得的最大值。由于每个状态下的宝石剩余的数量是可以确定的(因为到S就会被去掉),所以可以预处理一下每个状态下剩余的每个颜色的宝石的数量,接下来在当前状态下选择某一个包,看是否能产生出魔法石,如果能产生,那么他还可以在进行一个回合,所以dp[state]=max(dp[state],pt+f(state|(1<<i)))   (pt是当前产生魔法石的数量),如果不能,则下一回合是对方选择,所以dp[state]=max(dp[state],pt-f(st|(1<<i)))。

 

代码:

 

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<vector>
#define inf 0x3f3f3f3f
#define Inf 0x3FFFFFFFFFFFFFFFLL
#define eps 1e-9
#define pi acos(-1.0)
using namespace std;
typedef long long ll;
const int maxn=1<<21;
int color[10],bag[25][15],G,B,S;
int dp[maxn],remain[maxn][10];
bool vis[maxn];
int f(int st)
{
    if(vis[st]) return dp[st];
    if(st==((1<<B)-1))
    {
        return 0;
    }
    vis[st]=true;
    int &res=dp[st];
    res=inf;
    for(int i=0;i<B;++i)
    {
        if(!(st&(1<<i)))
        {
            int pt=0;
            for(int j=1;j<=bag[i][0];++j)
              remain[st][bag[i][j]]++;
            for(int j=0;j<=G;++j)
              pt+=remain[st][j]/S;
            for(int j=1;j<=bag[i][0];++j)
              remain[st][bag[i][j]]--;
            if(pt)
            {
                if(res==inf) res=pt+f(st|(1<<i));
                else res=max(res,pt+f(st|(1<<i)));
            }
            else
            {
                if(res==inf) res=pt-f(st|(1<<i));
                else res=max(res,pt-f(st|(1<<i)));
            }
        }
    }
    return res;
}
int main()
{
    //freopen("a.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    while(~scanf("%d%d%d",&G,&B,&S))
    {
        if(G==0&&B==0&&S==0) break;
        for(int i=0;i<B;++i)
        {
            scanf("%d",&bag[i][0]);
            for(int j=1;j<=bag[i][0];++j)
              scanf("%d",&bag[i][j]);
        }
        memset(remain,0,sizeof(remain));
        int total=1<<B,tmp;
        for(int i=0;i<total;++i)
        {
            tmp=i;
            int j=0;
            while(tmp)
            {
                if(tmp&1)
                {
                    for(int k=1;k<=bag[j][0];++k)
                     remain[i][bag[j][k]]++;
                }
                tmp>>=1;
                j++;
            }
            for(j=0;j<=G;++j)
              remain[i][j]%=S;
        }
        memset(vis,0,sizeof(vis));
        int ans=f(0);
        printf("%d\n",ans);
    }
    return 0;
}


 

你可能感兴趣的:(game)