【博弈 && dfs】POJ - 2068 Nim

Step1 Problem:

有 s 个石头,有 2*n 个人,分成两队交叉坐着分别是 1, 3, 5,…n-1. 和 2, 4, 6,…n. 第 i 个人可以拿走不多于 a[i] 个石头,从玩家 1 开始拿石头 1 到 2 到 3 到….n 到 1 一直循环,拿走最后一颗石头的团队失败。
数据范围:
1<=n<=10, 1<=a[i]<=16, 1<=s<=2^13

Step2 Ideas:

dp[s][i] == 1:当前到玩家 i 剩余 s 个石头必胜
dp[s][i] == 0:当前到玩家 i 剩余 s 个石头必败
dp[s][0] 就是结果
当前状态的下一个状态是必败状态,当前状态为必胜状态。
当前状态的下一个状态全是必胜状态,当前状态为必败状态。
然后搜索即可

Step3 Code:

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int N = 9000;
const int inf = 0x3f3f3f3f;
int a[100];
int dp[N][25], s, n;
int dfs(int x, int i)//剩余的石子,到第几个人
{
    //printf("%d %d\n", x, i);
    if(x <= 0) return dp[0][i] = 1;//已经没有石子可拿,所以当前状态必胜
    if(dp[x][i] != -1) return dp[x][i];//已经搜索过了不必再搜索了
    int res = inf;
    for(int j = 1; j <= a[i] && j <= x; j++)
    {
        res = min(res, dfs(x-j, (i+1)%(2*n)));
    }
    if(res == 0) return dp[x][i] = 1;//下一个状态存在必败状态,当前状态必胜
    else return dp[x][i] = 0;
}
int main()
{
    while(~scanf("%d", &n) && n)
    {
        memset(dp, -1, sizeof(dp));
        scanf("%d", &s);
        for(int i = 0; i < 2*n; i++)
            scanf("%d", &a[i]);
        dfs(s, 0);

        printf("%d\n", dp[s][0]);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/bbbbswbq/article/details/81054545