GYM 100827 G.Number Game(博弈论)

来源:互联网 发布:360全景软件 编辑:程序博客网 时间:2024/06/06 00:41

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 111int 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;}
0 0
原创粉丝点击