UVA 10404 - Bachet's Game 组合博弈

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

必败点(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 1000010
using 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 1000010
using 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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值