知道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;}
- 知道SG函数是干什么的
- getdtablesize()函数是干什么的
- sbrk() 函数是干什么的?
- MFC OnCmdMsg函数是干什么用的?
- 构造函数到底是干什么的?
- 新手配置JDK,虽然不知道是干什么用的
- 不知道干什么的时候要干什么
- 到底是干什么的
- 程序员是干什么的
- csdn 是干什么的??
- FastDFS 是干什么的?
- HttpContext是干什么的
- HttpContext是干什么的
- struts 是干什么的
- HttpContext是干什么的
- 主板驱动是干什么的?
- libx264是干什么的?
- javaldx是干什么的
- Codevs5230【三校联考试题】 猴子(重庆一中高2018级信息学竞赛测验8) 解题报告
- 线程同步实现
- JVM之Java类的加载
- mysql分库分表实战及php代码操作完整实例
- 160807
- 知道SG函数是干什么的
- 剑指Offer——栈的java实现和栈的应用举例
- C++内部培训小结
- digit之Dialog
- android仿乐视网弹幕的实现
- 【二叉树】二叉树排序树的判断、插入
- 机房总结(一)
- 侧滑菜单框架slidingMenu学习总结
- 状压DP——Corn Fields ( POJ 3254 )