hdu 4778 13杭州I题 状态压缩dp+博弈

分析:博弈的过程是一个树,而且要知道在最优策略情况下,肯定是选择了树上的某一条树枝,也就是一条路径。

所以我们可以用dp来找出某一条最优路径,而且我们可以发现2个人博弈的目的是为了让自己与另一个人的差值尽可能的大。

解法:用dp[i]表示状态i(能拿的置为1)的情况下先手减去后手分数的最大值。

初始化dp[(1<<n)-1] = 0;  我们可以预处理出sum[i]表示状态i的情况下有能获得的总共的分数。

对于dp[i],  选第j个包,  如果这次拿好分数增加tp, 那么用 dp[i]+tp 去转移 dp[i^(1<<j)], 

否则先后手交换, 用-dp[i]去更新dp[i^(1<<j)]。

杭电rank1  2100ms, 后来对预换了一种方法预处理sum数组, 845ms

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int G, B, S;
const int maxn = 1<<21;
int cnt[22];
int a[22][11];
int dp[maxn];
int sum[maxn];
int tp[9];
int two[22];
int res[maxn][9];
int Log[maxn];
int main() {
    int i, j;
    two[0] = 1;
    for(i = 1; i <= 21; i++)
        two[i] = two[i-1] << 1;
    Log[0] = -1;
    for(i = 1; i < two[21]; i++)
        Log[i] = Log[i>>1] + 1;
    while(~scanf("%d%d%d", &G, &B, &S)) {
        if(!G && !B && !S) break;
        for(i = 0; i < B; i++) {
            scanf("%d", &cnt[i]);
            memset(a[i], 0, sizeof(a[i]));
            for(j = 0; j < cnt[i]; j++) {
                int x;
                scanf("%d", &x);
                a[i][x]++;
            }
        }
        memset(res[0], 0, sizeof(res[0]));
        sum[0] = 0;
        for(i = 1; i < two[B]; i++) {
            int pre = i^(i&-i);
            sum[i] = sum[pre];
            int cur = Log[i&-i];
            for(j = 1; j <= G; j++)
                res[i][j] = res[pre][j] + a[cur][j];
        }
        for(i = 1; i <two[B]; i++) {
            sum[i] = 0;
            for(j = 1; j <= G; j++)
                sum[i] += res[i][j]/S;
        }

        for(i = 0; i < two[B]; i++) dp[i] = -1e9;
        dp[two[B]-1] = 0;
        for(i = two[B]-1; i >= 0; i--) {
            for(j = i; j; j -= j&-j) {
                int pre = i^(j&-j);
                int tp = sum[i] -sum[pre];
                if(tp > 0)
                    dp[pre] = max(dp[pre], dp[i]+tp);
                else
                    dp[pre] = max(dp[pre], -dp[i]);
            }
        }
        printf("%d\n", dp[0]);
    }
    return 0;
}


 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值