hdu 4778 Gems Fight!

           dp+博弈。首先我们发现,背包竟然只有21个。。。这样的话我们就可以用状态压缩表示当前状态都还剩下哪些背包了。然后对于当前状态,有两个转移方向:

           1、枚举背包,如果当前背包对cooker有影响的话,我们就会得到魔法石tmp个,这样的话下一步就还是当前人拿,这样的话就是dp[sta] = max(tmp + dp[sta ^ (1 << i)])。

         2、如果当前背包对cooker没有影响的话,那么如果下一个人拿到的最小的话,那么对于当前人来说就是这种情况能拿到的最大值了。于是dp[sta]=max(sum - dp[sta^(1 << i)]);(这样写关键是因为,最终得到的魔法石的总数是确定的)

#include
#include
#include
#include
#include
#include
#include
#include
#define REP(i, n) for(int i=0; i=b; i--)
#define LL long long
#define PB push_back
#define CLR(a, b) memset(a, b, sizeof(a))
using namespace std;

const int B = 23;
const int N = (1 << B);

bool vis[N];
int dp[N], b, g, s, n;
int sum[N], hav[B];
vector bg[B];

int calc(int tmp)
{
    int c[B], ret = 0; CLR(c, 0);
    for(int i = 0 ; i < b; i ++)
    {
        if((1 << i) & tmp)
        {
            for(int j = 0; j < hav[i]; j ++)
            {
                c[bg[i][j]] ++;
                ret += c[bg[i][j]] / s;
                c[bg[i][j]] %= s;
            }
        }
    }
    return ret;
}

int ok(int tmp, int i)
{
    return sum[tmp ^ (1 << i)] - sum[tmp];
}

int dfs(int sta, int sum)
{
    if(vis[sta]) return dp[sta];
    vis[sta] = 1;
    int &ret = dp[sta];
    ret = 0;
    for(int i = 0; i < b; i ++)
    {
        if(sta & (1 << i))
        {
            int tmp = ok(n ^ sta, i);
            if(tmp)
            {
                ret = max(ret, tmp + dfs(sta ^ (1 << i), sum - tmp));
            }
            else
            {
                ret = max(ret, sum - dfs(sta ^ (1 << i), sum));
            }
        }
    }
    return ret;
}

int main()
{
    while(scanf("%d%d%d", &g, &b, &s), b + g + s)
    {
        for(int i = 0; i < b; i ++)
        {
            scanf("%d", &hav[i]);
            bg[i].clear();
            for(int j = 0; j < hav[i];j ++)
            {
                int tmp;
                scanf("%d", &tmp);
                bg[i].PB(tmp);
            }
        }
        for(int i = 1; i < (1 << b); i ++)
        {
            sum[i] = calc(i);
        }
        n = (1 << b) - 1;CLR(vis, 0);
        printf("%d\n", 2 * dfs(n, sum[n]) - sum[n]);
    }
}


你可能感兴趣的:(博弈,动态规划,dp,博弈)