sg函数与博弈论2

参考链接:

http://blog.sina.com.cn/s/blog_51cea4040100h3l9.html

这篇主要就是讲anti-sg、multi-sg和every-sg的。

例1 poj3537

有一个长度为n的一维棋盘,两人轮流下子,如果一个人下了连在一起的三个子就立刻赢了,如果一个人下不了子了他就输了。3<=n<=2000

我们可以发现,如果我们在第i个地方落子,游戏就被分解为了两个子游戏:长度为i-3和n-i-2的两个子游戏。(至于为什么我也不好解释啊,就是如果之后都在这些地方下那么肯定i位置不会连成3子)

这样分解游戏的模型叫做multi-sg,它的sg函数定义是没什么区别的,可以直接刚。

2000的话平方裸搜就可以了。

//By zzq
#include <iostream>
#include <stdio.h>
#include <string.h>
using namespace std;
int sg[2333];
int tmd=0;
int gsg(int n)
{
    if(n<0) return 0;
    if(sg[n]>=0) return sg[n];
    bool ff[2001]={};
    for(int i=1;i<=n;i++) ff[gsg(i-3)^gsg(n-i-2)]=1;
    for(int i=0;;i++)
    {
        if(!ff[i]) return sg[n]=i;
    }
}
int main()
{
    memset(sg,-1,sizeof(sg));
    int n;
    scanf("%d",&n);
    if(gsg(n)) puts("1");
    else puts("2");
}

例2 bzoj1022

nim游戏,取到最后一粒石子的人输。

多组数据,n<=5000。

这个东西我们可以发现除了取到最后一粒石子的人输以外都是沙茶sg,所以我们就叫它anti-sg。

接下来就是结论啦,贾志豪神犇发明了一个sj定理可以解决这个问题:

对于任意一个anti-sg游戏,先手必胜当且仅当:

游戏的sg函数不为0且游戏中某个单一游戏的sg函数大于1;

游戏的sg函数为0且游戏中没有单一游戏的sg函数大于1。

这种结论题就直接做就是了。

//By zzq
#include <iostream>
#include <stdio.h>
#include <string.h>
using namespace std;
int T,n;
int main()
{
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        bool dy1=0;
        int ans=0;
        for(int i=1;i<=n;i++)
        {
            int x; scanf("%d",&x);
            ans^=x; dy1|=x>1;
        }
        if(((bool)ans)==dy1) puts("John"); else puts("Brother");
    }
}

every-sg没什么靠谱的例题啊...待补

posted @ 2016-06-14 19:10  fjzzq2002  阅读(423)  评论(0编辑  收藏  举报