UVA 10404 - Bachet's Game 组合博弈

来源:互联网 发布:台州电信网络测速 编辑:程序博客网 时间:2024/06/03 18:28

             杭电刘春英老师的课件中有:

必败点(P点) :前一个选手(Previous player)将取胜的位置称为必败点。
必胜点(N点) :下一个选手(Next player)将取胜的位置称为必胜点。

步骤1:将所有终结位置标记为必败点(P点);
步骤2: 将所有一步操作能进入必败点(P点)的位置标记为必胜点(N点)
步骤3:如果从某个点开始的所有一步操作都只能进入必胜点(N点) ,则将该点标记为必败点(P点) ;
步骤4: 如果在步骤3未能找到新的必败(P点),则算法终止;否则,返回到步骤2。
           按照这个模拟步骤写了个下面这个超时的代码

#include<cstdio>#include<iostream>#include<cstring>#include<set>#define MAXN 1000010using namespace std;int main(){    //freopen("in.txt","r",stdin);    set<int>win,lose;    bool vis[MAXN*2];    int n,m,p[11];    while(cin>>n>>m)    {        memset(vis,false,sizeof(vis));        win.clear();        lose.clear();        lose.insert(0);        vis[0]=true;        for(int i=0; i<m; i++)        {            int a;            cin>>a;            p[i]=a;            win.insert(a);            vis[a]=true;        }        int cur=0;        while(1)        {            if(vis[n])                break;            if(vis[cur])                cur++;            else            {                int flag=0;                for(int i=0; i<m; i++)                {                    if(cur>=p[i]&&!win.count(cur-p[i]))                    {                        flag=1;                        break;                    }                }                if(!flag)                {                    lose.insert(cur);                    vis[cur]=true;                    for(int i=0; i<m; i++)                    {                        win.insert(cur+p[i]);                        vis[cur+p[i]]=true;                    }                }                cur++;            }        }        if(win.count(n))            cout<<"Stan wins\n";        else cout<<"Ollie wins"<<endl;    }    return   0;}

          对于只剩i块石头时,i点要么是必胜点,要么是必败点,如果有一个p[ ],使得i-p[ ]块石头是个必败点,那么i点是个必胜点,否则就是个必败点。下面是AC代码:

#include<cstdio>#include<iostream>#include<cstring>#include<set>#define MAXN 1000010using namespace std;int main(){    //freopen("in.txt","r",stdin);    bool  f[1000010];    int p[11],m,n;    while(cin>>n>>m)    {        memset(f,false,sizeof(f));        for(int i=0; i<m; i++)        {            cin>>p[i];            f[p[i]]=true;        }        for(int i=1; i<=n; i++)        {            if(f[i]==true)  continue;            for(int j=0; j<m; j++)            {                if(i>=p[j]&&f[i-p[j]]==false)                {                    f[i]=true;                    break;                }            }        }        if(f[n]==true)            cout<<"Stan wins"<<endl;        else cout<<"Ollie wins"<<endl;    }    return   0;}