POJ.3537.Crosses and Crosses(博弈论 Multi-SG)

题目链接

\(Description\)

有一个一行n列的棋盘,每个人每次往上放一个棋子,将三个棋子连在一起的人赢。问是否有必胜策略。

\(Solution\)

首先一个人若在\(i\)处放棋子,那么另一个人就不能在\(i-2,i-1,i+1,i+2\)处放石子,这样会使对方赢。
那么可以看做:在\(i\)处放棋子后,另一个人不能选择\(i-2,i-1,i+1,i+2\)处放石子,不能放的人输。
可以联想到Nim游戏,一个人取一个石子,另一个人可取石子\(-2\);同时是产生两个局面
即1*n的棋盘上 在i处放棋子,会将游戏划分成\(s(i-3)+s(n-i-2)\)两个游戏
那这就是Multi-SG游戏,用SG函数解决。
记忆化,\(O(n^2)\).

Multi-SG游戏:

详细见这
Def: 在符合拓扑原则的前提下,一个单一游戏的后继可以为多个单一游戏。其余规则与SG游戏相同。
对于一个单一游戏,不同方法可能会将其划分为多个单一游戏。每一方法对应的多个单一游戏的(异或)和即可表示这种方法的NP状态。
而这个单一游戏的SG值为其所有方法的SG值的mex

//1692K 266MS
#include <cstdio>
#include <cstring>
const int N=2002;

int n,sg[N];

int Get_SG(int x)
{
    if(x<0) return 0;
    if(~sg[x]) return sg[x];
    bool vis[N];
    memset(vis,0,sizeof vis);
    for(int i=1; i<=x; ++i)//放所有位置都是子局面 
        vis[Get_SG(i-3)^Get_SG(x-i-2)]=1;//x为偶数时会有重 不过记忆化 无妨 
    for(int i=0; ; ++i)
        if(!vis[i]) return sg[x]=i;
}

int main()
{
    while(~scanf("%d",&n))
        memset(sg,0xff,sizeof sg), puts(Get_SG(n)?"1":"2");
    return 0;
}

转载于:https://www.cnblogs.com/SovietPower/p/8470527.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值