11年成都 A 博弈论+记忆化搜索 HDU 4111

博弈
赛中的时候第一反应是结论题,但是跑了几个样例没跑出来
于是试着从算法方面入手。
大概猜测和堆数与石子数的总和有关,但是第一个和第三个样例告诉我应该不是简单的求和关系。
可能是记忆化搜索,但是状态过多实在不知道如何存储,然后就弃疗了……

题解是这样的
发现如果当前没有石子是一个,且(石子堆数 + 石子总数 - 1)为偶数,则是必胜状态。
这是整个算法的基础。
但是现在有一些石子堆只有1个石子,取了该石子,相当于一次进行了两次操作。
所以设dp[i][j],i表示有多少个只有1个石子的石堆,j表示(石子数大于1的石子堆+这些石子堆的石子总和-1)。
值域为0,1。0表示必败,1表示必胜。
那么,接下来就是枚举当前操作进行记忆化搜索。

失分点/学习点:
1. 没有建立好整个模型,没弄清楚博弈最基本的必胜状态。
2. 在记忆化搜索的过程中,状态转移方程比较多没有列全。

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 50 + 2;
const int MAXM = 1000 + 2;
int dp[MAXN][MAXM * MAXN];
int dfs(int one, int sum)
{
//    printf("one = %d, sum = %d\n", one, sum);
//    system("pause");
    if(sum == 1) one++, sum--;
    if(dp[one][sum] != -1) return dp[one][sum];
    if(one == 0) return dp[one][sum] = (sum % 2 == 0 ? 0 : 1);
    else if(sum && dfs(one - 1, sum + 1) == 0) return dp[one][sum] = 1;
    else if(dfs(one - 1, sum) == 0) return dp[one][sum] = 1;
    else if(sum && dfs(one, sum - 1) == 0) return dp[one][sum] = 1;
    else if(one >= 2 && sum && dfs(one - 2, sum + 3) == 0) return dp[one][sum] = 1;
    else if(one >= 2 && sum == 0 && dfs(one - 2, sum + 2) == 0) return dp[one][sum] = 1;
    else return dp[one][sum] = 0;
}
int main()
{
    memset(dp, -1, sizeof dp);
    int T; scanf("%d", &T);
    for(int cas = 1 ; cas <= T ; cas++) {
        int n; scanf("%d", &n);
        int sum = 0, one = 0;
        for(int i = 0 ; i < n ; i++) {
            int u; scanf("%d", &u);
            if(u == 1) one++;
            else sum += u + 1;
        }
//        dfs(one, sum);
//        for(int i = 0 ; i <= one ; i++) {
//            for(int j = 0 ; j <= sum + one + 1 ; j++) printf("%d ", dfs(i, j));
//            printf("\n");
//        }
        if(sum) sum--;
//        printf("cas = %d, one = %d, sum = %d\n", cas, one, sum);
        if(dfs(one, sum) == 1) printf("Case #%d: Alice\n", cas);
        else printf("Case #%d: Bob\n", cas);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值