toj 1017. Number Game

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;

}

 

你可能感兴趣的:(number)