知道SG函数是干什么的

来源:互联网 发布:阿里云centos安装lamp 编辑:程序博客网 时间:2024/05/07 19:59

          看了几天博弈论,今天突然豁然开朗,充分理解了SG函数,网上有讲得很好的博弈,三种基本博弈在看完后应该会理解,但是对于理解SG函数,这个链接讲的很

不错,(http://www.cnitblog.com/weiweibbs/articles/42735.html),看第一遍的时候,没人可以看的很明白,所以一定要自己在纸上根据其定义算出几个数的sg值,

例如可选步数集合为{1, 2, 3},算出0到8的sg值,结果如下:

x                0    1    2    3    4    5    6    7    8

g(x)           0    1    2    3    0    1    2    3    0

          然后根据计算结果,将上面的那个博客链接里的这段话(首先,所有的terminal position所对应的顶点,也就是没有出边的顶点,其SG值为0,因为它的后继集合是

空集。然后对于一个g(x)=0的顶点x,它的所有后继y都满足g(y)!=0。对于一个g(x)!=0的顶点,必定存在一个后继y满足g(y)=0)挨个字的看,看完这段话就会恍然大悟,知

道sg函数到底是干什么的。然后我想说,上面那个计算的例子其实就是巴什博奕用SG函数来做,他的SG值就是n%(k+1);

          理解了SG函数后,对于组合博弈就可以解决了,但一定要记住那句话(游戏的和的SG函数值就是它的所有子游戏的SG函数值的异或),这句话很重要,也是SG的

精髓,知道这个后就可以解决下面两道关于SG函数的题了;


poj 2311 链接  http://acm.hust.edu.cn/vjudge/problem/17242;

题目大意就是说给定一个矩形纸片,然后每个人轮流剪,谁最后剪到1*1就胜利,显然最终状态为(2,2)(2,3)(3,2)时为必输态,所以根据矩形长宽计算其SG值,

然后判断状态就可以了。代码如下:

#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>#include <cmath>using namespace std;int sg[205][205];int vis[205];int Sg(int n, int m){    if(sg[n][m] != -1)        return sg[n][m];    memset(vis, 0, sizeof(vis));    for(int i=2; i<=n-i; ++i)    {        vis[(Sg(i, m) ^ Sg(n-i, m))] = 1;    }    for(int i=2; i<=m-i; ++i)    {        vis[(Sg(n, i) ^ Sg(n, m-i))] = 1;    }    for(int i=0; i<205; ++i)        if(!vis[i])        {            sg[n][m] = i;            return i;        }}int main(){    int w, h;    memset(sg, -1, sizeof(sg));    sg[2][2] = sg[2][3] = sg[3][2] = 0;    while(scanf("%d%d", &w, &h)!=EOF)    {        if(Sg(w, h))            printf("WIN\n");        else            printf("LOSE\n");    }    return 0;}

还有一道类似的题目,hdu 5795 链接:

题目大意,两个人玩改进版的尼姆博弈游戏,在原先的基础上,某个人可以将一堆石子分为非空的三堆,然后判断输赢,这道题可以考虑在一堆的情况下的SG值,打表后

会发现规律,打表代码如下

#include <iostream>#include <cstdio>#include <cstring>#include <cmath>#include <algorithm>using namespace std;int sg[110];bool vis[1100];int Sg(int x){    memset(vis, 0, sizeof(vis));    for(int i=0; i<x; i++)    {        vis[sg[i]] = true;    }    int ans;    for(int i=1; i<x; i++)    {        for(int j=1; j+i<x; j++)        {            vis[sg[i]^sg[j]^sg[x-i-j]] = true;        }    }    for(int i=0; i<=1000; i++)        if(!vis[i])            return i;}int main(){    memset(sg,-1,sizeof(sg));    sg[0] = 0;    for(int i=1; i<=100; i++)    {        sg[i] = Sg(i);    }    for(int i=0; i<=100; i++)    {        printf("sg[%d] = %d\n", i, sg[i]);    }    return 0;}

ac代码如下:

#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>#include <cmath>using namespace std;int main(){    int T, n, t;    scanf("%d", &T);    while(T--)    {        scanf("%d", &n);        int sum = 0;        for(int i=1; i<=n; ++i)        {            scanf("%d", &t);            if(t%8 == 0) t--;            else if(t%8 == 7) t++;            sum ^= t;        }        if(sum)            printf("First player wins.\n");        else            printf("Second player wins.\n");    }    return 0;}


 

2 0
原创粉丝点击