toj 1017. Number Game

原文链接: http://www.cnblogs.com/liulangye/archive/2012/10/09/2717316.html

http://202.113.2.5:57778/toj/showp1017.html

DP (状态压缩+记忆化搜索) + 博弈论

基本思路:

用状态压缩表示 那些是还可以选的 哪些是不可以选的

在更新过程中 标记 是否是奇异状态

代码及其注释:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<vector>
#include<queue>
#include<map>
#include<stack>
#include<algorithm>

using namespace std;
//#pragma comment(linker,"/STACK:1000000000,1000000000")

#define LL long long

const int INF=0x3f3f3f3f;
const int M=20;
const int N=(1<<M)-1;
int fail[N+10];//0 为初始化 1 表示奇异状态 -1 表示非奇异状态
bool can[25];//标记
int Fnext(int x,int l)//在x状态下 选择数字 l+1 (既用位运算表示左移 l 位) 时得到新的状态
{
    int temp=x;
    temp=temp|(1<<l);
    for(int i=1;i<M;++i)
    {
        if((temp&(1<<i))&&(i+l+1)<20)
        {
            temp=temp|(1<<(i+l+1));
        }
    }
    return temp;
}
int dp(int x)//求是否是奇异状态
{
    if(fail[x]!=0)
    return fail[x];
    if(x==N)
    {
        fail[x]=1;
        return fail[x];
    }
    for(int l=1;l<M;++l)
    {
        if((x&(1<<l)))
        continue;
        int temp=Fnext(x,l);
        if(dp(temp)==1)//有任一个可能更新到奇异状态 则当前状态为非奇异状态
        fail[x]=-1;
    }
    if(fail[x]==0)//否则为奇异状态
    fail[x]=1;
    return fail[x];
}
int main()
{
    //freopen("data.txt","r",stdin);
    memset(fail,0,sizeof(fail));
    int T;
    scanf("%d",&T);
    for(int ca=1;ca<=T;++ca)
    {
        int n;
        scanf("%d",&n);
        memset(can,false,sizeof(can));
        while(n--)
        {
            int temp;
            scanf("%d",&temp);
            if(temp<=20&&temp>1)
            can[--temp]=true;
        }
        int k=0;
        for(int i=1;i<M;++i)
        {
            if(can[i]==false)
            k=Fnext(k,i);
        }
        printf("Scenario #%d:\n",ca);
        if(dp(k)==1)//当前为奇异状态
        {
            printf("There is no winning move");
        }else
        {
            printf("The winning moves are:");
            for(int l=1;l<M;++l)
            {
                if((k&(1<<l)))
                continue;
                int temp=Fnext(k,l);//非奇异状态的话 看有哪几个选择
                if(dp(temp)==1)
                printf(" %d",l+1);
            }
        }
        printf(".\n\n");
    }
    return 0;
}

转载于:https://www.cnblogs.com/liulangye/archive/2012/10/09/2717316.html

猜你喜欢

转载自blog.csdn.net/weixin_30294709/article/details/94791711