HDU-4778 Gems Fight!

本文通过状态压缩动态规划解决了一个涉及石头颜色、数量与魔法石生成的博弈问题。详细阐述了问题背景、解题思路及核心算法,旨在提供一种高效解决此类问题的方法。

题目:

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

题意:

有b个盒子,每个盒子中有一些石头,石头颜色共有g种颜色,二人轮流把其中一个盒子的石头放入锅中,每s个相同颜色的石头可以生成一种魔法石。

每个人放入一盒石头后的得分为当前生成的魔法石数,如果生成了魔法石可以再放一盒石头。求第一个人得分减去第二个人分数的最大值。

思路:

首先发现这道题的时间是10s,颜色盒子也最多只有21个,所以可以考虑直接状压dp。

主要就是考虑状态转移方程,因为可以连续取盒子,所以方程要分成能生成魔法石和不能生成魔法石两种。

二人的取法都是最优的,所以取得每个状态的分数一定有最大差值。

令dp[i]为第一个人取到 i 状态时第一人得分减去第二人得分的最大值。

如果 j 状态取到 i 状态能够生成魔法石,dp[i] = max(dp[i], res+dp[j]);

如果 j 状态取到 i 状态不能生成魔法石,则相当于 j 状态是第二个人取到的,dp[i] = max(dp[i], res-dp[j]);

j 状态时取第k个盒子得到i状态相当与 j = i^(1<<k);

代码:

#define INF 0x3f3f3f3f
#define N 22

int n,m,g,b,s;
int dp[1<<N],now[N],init[N][N],sum[N];

int main()
{
    int i,j,k,kk,t,x,y,z;
    while(scanf("%d%d%d",&g,&b,&s)!=EOF&&g)
    {
        memset(init,0,sizeof(init));
        for(i=0;i<b;i++)
        {
            scanf("%d",&n);
            for(j=0;j<n;j++)
            {
                scanf("%d",&m);
                init[i][m]++;
            }
        }
        dp[0] = 0;
        for(i=1;i<1<<b;i++)
        {
            dp[i]=-INF;
            memset(sum,0,sizeof(sum));
            for(j=0;j<b;j++)
                if(!(i&(1<<j)))
                    for(k=1;k<=g;k++)
                        sum[k]+=init[j][k];
            for(j=1;j<=g;j++)
                sum[j]%=s;
            for(j=0;j<b;j++)
                if(i&(1<<j))
                {
                    memcpy(now,sum,sizeof(sum));
                    int res=0;
                    for(k=1;k<=g;k++)
                    {
                        now[k]+=init[j][k];
                        res+=now[k]/s;
                    }
                    if(res>0)dp[i] = max(dp[i],res+dp[i^(1<<j)]);
                    else dp[i] = max(dp[i],res-dp[i^(1<<j)]);
                }
        }
        printf("%d\n",dp[(1<<b)-1]);
    }
    return 0;
}













评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值