组合博弈入门

一、博弈论三条性质:

  • 终结点为P点

  • P点只能到N点

  • N点至少有一种途径到P点

N:必胜态 P:必败态

  

1、引导题

1846 Brave Game

题目大意:
n个石子两人轮流取1~m个,最后取空的胜利n:23  m:2
0:P      //终结点
1:N
2:N
3:P
4:N
5:N
6:P结论: x % (m + 1) == 0 则为P点
#include <iostream>
#include <cstdio>using namespace std;int main() {int t, n, m;cin >> t;while (t--) {cin >> n >> m;cout << (n % (m + 1) ? "first" : "second") << endl;}return 0;
}

2、引导题

1847 Good Luck in CET-4 Everybody!

题目大意:
n张纸牌两人轮流取2的幂次(1, 2, 4, 8, 16……),最后取空的胜利同理上一题取石子
0 1 2 3 4 5 6 7 8 9 10 11 12 13
P N N P N N P N N P N  N  P  N
结论: n % 3 == 0 则为P点
#include <iostream>
#include <cstdio>using namespace std;int main() {int n;while (cin >> n) {cout << ((n % 3) ? "Kiki" : "Cici") << endl;}return 0;
}

  

  

二、NIM博弈

定理: 如果先手必胜,则有 A 1 x o r A 2 x o r . . . A n ≠ 0 A_1\ xor \ A_2\ xor\ ...\ A_n\ \ne\ 0 A1​ xor A2​ xor ... An​ = 0

  就是控0,所有堆都为空时异或为0。只要还剩石子,并且异或为0,那么至少还有两堆,或者说一次必取不完局面。就把这种局面一直扔给对手,使自己保证永远不败状态,此时无论对手怎么取,异或都不为0。

27:    11011  num[0]
8:    01000  num[1]
20:   10100  num[2]
13:   01101  num[3]---- ^
10:   01010  sumnim[i] > (nim[i] ^ sum) 为可选方案  注意:运算符优先级
nim[i] = nim[i] ^ sum 为具体调整方案

  

1、先手状态判定

1849 Rabbit and Grass

题目大意:
n堆石子,两人轮流选一堆取走任意个,最后取空的胜利,问先手必赢还是必输解题思路:NIM博弈
#include <iostream>
#include <cstdio>using namespace std;int main() {int n;while (cin >> n && n) {int Xor = 0, x;while (n--) {cin >> x;Xor ^= x;}cout << (Xor ? "Rabbit Win!" : "Grass Win!") << endl;}return 0;
}

  

2、先手必胜第一手方案数

1850 Being a Good Boy in Spring Festival

题目大意:
nim博弈如果先手必胜的话,那么输出第一步用多少种选择。反之先手必败输出0
#include <iostream>
#include <cstdio>using namespace std;#define N 100int nim[N +  10];int main() {int n;while (scanf("%d", &n) && n) {int sum = 0, ans = 0;for (int i = 0; i < n; ++i) {scanf("%d", nim + i);sum ^= nim[i];}for (int i = 0; i < n; ++i) {if (nim[i] > (nim[i] ^ sum))  ++ans;//nim[i] = nim[i] ^ sum 为具体调整方案}printf("%d\n", ans);}return 0;
}

  

  

  

三、SG函数

有向图游戏

​ 给定一个有向无环图,图中有一个唯一的起点,在起点上放有一枚棋子。两名玩家交替地把这枚棋子沿有向边进行移动,每次可以移动一步,无法移动者判负。该游戏被称为有向图游戏。
​ **任何一个公平组合游戏都可以转化为有向图游戏。**具体方法是,把每个局面看成图中的一个节点,并且从每个局面向沿着合法行动能够到达的下一个局面连有向边。

Mex运算

​ 设 S S S​​​ 表示一个非负整数集合。定义 M e x ( S ) Mex(S) Mex(S)​ 为求出不属于集合 S S S​ 的最小非负整数的运算。

SG函数

​ 在有向图游戏中,对于每个节点 x x x , 设从 x x x 出发共有 k k k 条有向边,分别到达节点 y 1 , y 2 , . . . , y k y_1,y_2,...,y_k y1​,y2​,...,yk​,定义 S G ( x ) SG(x) SG(x)为 x x x 的后继节点 y 1 , y 2 , . . . , y k y_1,y_2,...,y_k y1​,y2​,...,yk​ 的 S G SG SG函数值构成的集合再执行$Mex\ ​运算的结果,即 ​运算的结果,即 ​运算的结果,即SG(x)=Mex({SG(y_1),SG(y_2),…,SG(y_k)})$​

​ 特别的,整个有向图游戏 G G G​​​ 的 S G SG SG 函数值被定义为有向图游戏起点 s s s 的 S G SG SG 函数值,即 S G ( G ) = S G ( s ) SG(G) = SG(s) SG(G)=SG(s)​

​ 有向图游戏的和:设 G 1 , G 2 , . . . , G m G_1, G2, ... ,G_m G1​,G2,...,Gm​​是 m m m​ 个有向图游戏。定义有向图游戏 G G G​,它的行动规则是任选某个有向图游戏 G i G_i Gi​​,并在 G i G_i Gi​​上行动一步。 G G G​ 被称为有向图游戏 G 1 , G 2 , … , G m G_1,G_2,…,G_m G1​,G2​,…,Gm​​ 的和

​ 有向图游戏的和的 S G SG SG​​函数值等于它包含的各个子游戏 S G SG SG​函数值的异或和,即: S G ( G ) = S G ( G 1 ) x o r S G ( G 2 ) x o r . . . x o r S G ( G m ) SG(G)= SG(G_1) \ xor\ SG(G_2) \ xor\ ...\ xor\ SG(G_m) SG(G)=SG(G1​) xor SG(G2​) xor ... xor SG(Gm​)​

​ 定理

有向图游戏的某个局面必胜,当且仅当该局面对应节点的 S G SG SG​​函数值大于 0 0 0

有向图游戏的某个局面必败,当且仅当该局面对应节点的 S G SG SG​函数值等于 0 0 0​

​ 我们不再详细证明该定理。读者可以这样理解:
​ 在一个没有出边的节点上,棋子不能移动,它的 S G SG SG​​​​​​值为 0 0 0​​​​​​,对应必败局面。若一个节点的某个后继节点 S G SG SG​​​​​​值为 0 0 0​​​​​​,在$\ Mex\ ​​​​​​运算后,该节点的 ​​​​​​运算后,该节点的 ​​​​​​运算后,该节点的SG$​​​​​​值大于 0 0 0​​​​​​.这等价于,若一个局面的后继局面中存在必败局面,则当前局面为必胜局面。
​ 若一个节点的后继节点 S G SG SG​​​​值均不为 0 0 0​​​,在$\ Mex\ ​运算后,该节点的 ​运算后,该节点的 ​运算后,该节点的SG$​值为 0 0 0。这等价于,若一个局面的后继局面全部为必胜局面,则当前局面为必败局面。
  

1、多堆取石子

1848 Fibonacci again and again

题目大意:
三堆石子,两人轮流取f个,最后取空的胜利
f[1] = 1, f[2] = 2, f[3] = 3, f[4] = 5, ... , f[n] = f[n - 1] + f[n - 2]解题思路:SG函数

#include <iostream>
#include <cstdio>
#include <cstring>using namespace std;#define N 1000int SG[N + 10], flag[N + 10], fib[N];void Get_Fib() {fib[1] = 1;fib[2] = 2;for (int i = 3; fib[i - 1] < N; ++i)  fib[i] = fib[i - 1] + fib[i - 2];return ;
}void Get_SG() {for (int i = 1; i <= N; ++i) {memset(flag, 0, sizeof(flag));for (int j = 1; i - fib[j] >= 0; ++j)  flag[SG[i - fib[j]]] = 1;int ind = 0;while (flag[ind])  ++ind;SG[i] = ind;}return ;
}int main() {Get_Fib();Get_SG();int m, n, p;while(scanf("%d%d%d", &m, &n, &p) && m && n && p) {printf("%s\n", SG[m] ^ SG[n] ^ SG[p] ? "Fibo" : "Nacci");}return 0;
}

  

2、拍卖会

2149 Public Sale

题目大意:
底价为0,轮流加价1~m,率先加到不小于n的胜利。依次输出先手必胜的情况第一次可以叫的价钱,如果先手必败输出none解题思路:
以终点n作为博弈起点,倒序求SG值
SG yyds!
#include <iostream>
#include <cstdio>
#include <cstring>using namespace std;#define N 1100int SG[N + 10], flag[N + 10];void Get_SG(int n, int m) {for (int i = n; i > 0; --i) {memset(flag, 0, sizeof(flag));for (int j = 1; j <= m && i + j <= n; ++j) {flag[SG[i + j]] = 1;}for (int j = 0; ; ++j) {if (flag[j] == 0) {SG[i] = j;break;}}}return ;
}int main() {int n, m;while (~scanf("%d%d", &n, &m)) {if (m >= n) {for (int i = n; i <= m; ++i) {if (i - n)  putchar(' ');printf("%d", i);}putchar('\n');continue;}Get_SG(n, m);bool is = true;for (int i = 1; i <= m; ++i) {if (SG[i])  continue;if (!is)  putchar(' ');printf("%d", i);is = false;}if (is)  printf("none\n");else  putchar('\n');}return 0;
}

  

3、志愿者选拔

2188 悼念512汶川大地震遇难同胞——选拔志愿者

题目大意:
低价为0,轮流加价1~m,率先加到不小于n的胜利。先手必胜输出Grass,反之Rabbit
#include <iostream>
#include <cstdio>
#include <cstring>using namespace std;#define N 10000
#define M 10        //注意这里可以节约空间花销,m<=10,一个点最多十个后继,SG值不可能大于等于10int SG[N + 10], flag[M + 10];void Get_SG(int n, int m) {for (int i = n; i > 0; --i) {memset(flag, 0, sizeof(flag));for (int j = 1; j <= m && i + j <= n; ++j) {flag[SG[i + j]] = 1;}for (int j = 0; ; ++j) {if (flag[j])  continue;SG[i] = j;break;}}return ;
}int main() {int t, n, m;cin >> t;while (t--) {scanf("%d%d", &n, &m);if (m >= n)  printf("Grass\n");else {Get_SG(n, m);bool is = 0;for (int i = 1; i <= m; ++i) {if (SG[i])  continue;is = 1;break;}printf("%s\n", is ? "Grass" : "Rabbit");}}return 0;
}

  

4、组合博弈

1536 S-Nim

1944 S-Nim

题目大意:
5 1 2 3 4 5   //5种取子规则
3             //3次询问
2 5 12        //第一次 2堆石子 分别5和12块石子
3 2 4 7       //第二次
4 2 3 7 12    //第三次
0             //输入0结束记忆化搜索SG值,只计算用到的SG值,没有用到的SG值不计算,减少了部分时间开销
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>using namespace std;#define N 10000
#define M 100int vis[M + 5], SG[N + 5];   //vis取子规则 int Get_SG(int x, int &k) {if (~SG[x])  return SG[x];int flag[M + 5] = {0};for (int i = 1; i <= k && x - vis[i] >= 0; ++i) {flag[Get_SG(x - vis[i], k)] = 1;}int ind = 0;while (flag[ind])  ++ind;return SG[x] = ind;
}int main() {int k, t;while (scanf("%d", &k) && k) {memset(SG, -1, sizeof(SG));SG[0] = 0;for (int i = 1; i <= k; ++i)  scanf("%d", vis + i);sort(vis + 1, vis + k + 1);    //取子规则需提前排序scanf("%d", &t);while (t--) {int n, Xor = 0;scanf("%d", &n);for (int i = 1, x; i <= n; ++i) {scanf("%d", &x);Xor ^= Get_SG(x, k);}printf("%c", Xor ? 'W' : 'L');}putchar('\n');}return 0;
}

博弈论(Bash博弈、Nim博弈、SG函数、组合博弈)相关推荐

  1. 三个常见博弈游戏以及 SG 函数和 SG 定理

    前言 原文章 通过数论或者自然数性质完美解决的三个常见博弈游戏: 博弈 解决方法 Bash Game 同余理论 Nim Game 异或理论 Wythoff Game 黄金分割 Bash Game 描述 ...

  2. 【甜椒ACM】博弈论入门(Nim、sg定理)

    博弈论入门(Nim.sg定理) 通常由以下形式构成:给定一个游戏规则,甲.乙轮流出手行动,最后无法行动的人失败,问获胜方是谁/是否存在先手必胜策略等等. 游戏的前提是,默认"双方都最聪明&q ...

  3. NIM数字游戏 SG函数 有向图博弈 学习记录

    写在前面:很早之前我就想写一写博弈论的学习记录了.本篇文章记录了我在学习博弈论初步时的顺序,现在网络上的博弈论资料大多都是从SG函数开始讲解,而我谜一样的学习方法让我对博弈论初步有了不同的理解过程,所 ...

  4. (转)博弈问题与SG函数

    博弈问题 若你想仔细学习博弈论,我强烈推荐加利福尼亚大学的Thomas S. Ferguson教授精心撰写并免费提供的这份教材,它使我受益太多.(如果你的英文水平不足以阅读它,我只能说,恐怕你还没到需 ...

  5. 博弈问题及SG函数(真的很经典)

    博弈问题 若你想仔细学习博弈论,我强烈推荐加利福尼亚大学的Thomas S. Ferguson教授精心撰写并免费提供的这份教材,它使我受益太多.(如果你的英文水平不足以阅读它,我只能说,恐怕你还没到需 ...

  6. 博弈问题及SG函数(怒赞,耐心地仔细看一定能看懂)

    博弈问题 若你想仔细学习博弈论,我强烈推荐加利福尼亚大学的Thomas S. Ferguson教授精心撰写并免费提供的这份教材,它使我受益太多.(如果你的英文水平不足以阅读它,我只能说,恐怕你还没到需 ...

  7. HDU - 1079 Calendar Game(博弈打表sg函数)

    题目链接:点击查看 题目大意:给出一个日期,两个人轮流按照规则操作,具体规则如下: 每次可以增加一天 每次可以增加一个月到下一个月的当天 首先到达2001年11月4日的人获胜,问谁能获胜 题目分析:因 ...

  8. POJ 3553 Light Switching Game 博弈论 nim积 sg函数

    http://poj.org/problem?id=3533 变成三维的nim积..前面hdu那个算二维nim积的题的函数都不用改,多nim积一次就过了...longlong似乎不必要但是还是加上了 ...

  9. 组合博弈游戏 - SG函数和SG定理

    转载来自:http://blog.csdn.net/luomingjun12315/article/details/45555495 在介绍SG函数和SG定理之前我们先介绍介绍必胜点与必败点吧. 必胜 ...

  10. 博弈论与SG函数(Nim游戏)

    博弈论与SG函数(Nim游戏) 目录 博弈论与SG函数(Nim游戏) 游戏状态 状态图(SG图) Nim 游戏 Nim 和 SG函数 Grundy数字 组合博弈游戏 Grundy 游戏 例题 在本篇, ...

最新文章

  1. DBA_Oracle Database 11g 面向 DBA 和开发人员的重要特性
  2. 在Ubuntu下解决E: 无法对目录 /var/lib/apt/lists/ 加锁的问题
  3. 【CF671D】 Roads in Yusland(对偶问题,左偏树)
  4. C语言经典例22-乒乓球比赛名单问题
  5. 一 SpringMVC源码之DispatcherServlet AbstractHanderMapping
  6. error while loading shared libraries的解決方法
  7. linux 线程pthread_detach,linux线程之pthread_join和pthread_detach
  8. Repeater 得到checkbox值
  9. 编程语言的发展趋势及未来方向(7):总结
  10. CentOS平滑更新nginx版本
  11. C语言算三角形外心坐标,三角形外心坐标公式(含C语言代码)
  12. matlab 平滑曲线连接_科研画图-率失真曲线图改进:散点连接成曲线并画出原散点的标记点(基于Matlab)...
  13. ecshop flow.php goods_number,ecshop二次开发属性库存缺货的思路
  14. Java Web三大组件
  15. NeRF 从入门到精通
  16. HTML制作简单课程表
  17. 计算机自动重启快捷键,什么是笔记本电脑重启快捷键
  18. java spring登录验证_详解使用Spring Security进行自动登录验证
  19. java nas_NAS对家庭来说有什么用处?
  20. easypoi 实现多sheet导出excel

热门文章

  1. 【树莓派】树莓派4配件,简单汇总玩树莓派4需要购买的配件
  2. 语言学a b和c级期刊分类,中文学术期刊目录共分为A、B、C、D四类.doc
  3. 【转】Golang汇编命令解读
  4. 短视频配音用什么软件好?短视频配音软件免费哪款好用?
  5. 设计原则之依赖倒置原则的概念及实例代码操作
  6. 基于Spring MVC + Spring + MyBatis的【密室逃脱游戏主题排行榜】
  7. 每天学一点flash(5) actionscript 3.0 外部加载mp3音乐
  8. 【国际】加拿大声明代币可能属于证券并公布辨别方法
  9. 编译原理之 短语直接短语句柄 定义与区分
  10. 【程序12】模拟掷骰子游戏