GYM 101653 Q.Number Game(博弈论)

Description
一个1~n的排列,每次可以拿走一个数当且仅当这个数大于其两边位置的数(0和n+1位置认为是0),一个数被拿走之后可以认为这个位置的数是0,Alice和Bob轮流拿,谁拿走1谁赢,Alice先手,在双方足够机智的条件下问谁必胜
Input
第一行一整数T表示用例组数,每组用例首先输入一整数n,之后一个1~n的排列(1<=T<=100,1<=n<=100)
Output
输出必胜者
Sample Input
4
4
2 1 3 4
4
1 3 2 4
3
1 3 2
6
2 5 1 6 4 3
Sample Output
Bob
Alice
Bob
Alice
Solution
记dp[l][r][last]表示区间[l,r]被独立出来(即l-1和r+1位置都是0)且其他位置非零数剩下last个的必胜状态(1表示Alice必胜,0表示Bob必胜),那么答案就是dp[1][n][0],而每种状态有两种后继状态,一是从[l,r]中拿走一个合法的数,二是从last个数中拿走一个(随便拿,不会影响[l,r]),如果所有后继都是必胜态则当前是必胜态,否则当前是必胜态,记忆化一下即可
Code

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<ctime>
using namespace std;
typedef long long ll;
#define INF 0x3f3f3f3f
#define maxn 111
int T,n,pos,a[maxn],dp[maxn][maxn][maxn];
int dfs(int l,int r,int last)
{
    if(dp[l][r][last]>=0)return dp[l][r][last];
    if(l==r)return dp[l][r][last]=1;
    int ans=0;
    for(int i=l;i<=r;i++)
    {
        if(i==l&&a[l]>=a[l+1])ans|=dfs(l+1,r,last)^1;
        else if(i==r&&a[r]>=a[r-1])ans|=dfs(l,r-1,last)^1;
        else if(a[i]>=a[i-1]&&a[i]>=a[i+1])
        {
            if(i>pos)ans|=dfs(l,i-1,last+r-i)^1;
            else ans|=dfs(i+1,r,last+i-l)^1;
        }
    }
    if(last)ans|=dfs(l,r,last-1)^1;
    return dp[l][r][last]=ans;
}
int main()
{
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            if(a[i]==1)pos=i;
        }
        memset(dp,-1,sizeof(dp));
        printf("%s\n",dfs(1,n,0)?"Alice":"Bob");
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/v5zsq/article/details/80407006