Nim 博弈和 sg 函数
sg 函数
几类经典的博弈问题
- 阶梯博弈: 只考虑奇数号楼梯Nim,若偶数楼梯只作容器,那么游戏变为Nim。题目
- 翻转硬币: 局面的SG值为局面中每个正面朝上的棋子单一存在时的SG值的异或和。题目
- Multi-SG游戏: 对于一个单一游戏,不同的方法可能会将其分成不同的多个单一游戏。每一方法对应的多个单一游戏的游戏的和即可以表示这种方法的NP状态。而这个单一游戏的SG函数即为未在所有方法的SG函数值中出现过的最小值。题目
- Anti-SG游戏和SJ定理 (在论文中有详细的论述和证明)
- Every-SG游戏: 对于Every-SG游戏先手必胜当且仅当单一游戏中最大的step为奇数。题目
- 树的删边游戏: 叶子节点的SG值为0;中间节点的SG值为它的所有子节点的SG值加1后的异或和。题目
- 无向图的删边游戏: 我们可以对无向图做如下改动:将图中的任意一个偶环缩成一个新点,任意一个奇环缩成一个新点加一个新边;所有连到原先环上的边全部改为与新点相连。这样的改动不会影响图的SG 值。
题目
hdu3032
题意
Multi-SG
给 n 堆石子, 每次有两步可选的操作,
- 将一堆 石子分成两堆
- 拿走一堆石子的任意个
最后不能行动的输。
分析
看完论文就会做了,
一堆石子数量为2 时 的后继有:0,1和(1,1),他们的SG值分别为0,1,0,所以sg(2) =2。
一堆石子数量为3 时的后继有:0、1、2、(1,2),他们的SG值分别为0、1、2、3,所以sg(3) = 4。
一堆石子数量为4 时的后继有:0、1、2、3、(1,3)和(2,2),他们的SG值分别为0,1,2,4,5,0,所以sg(4) = 3.
打表可以找到规律,见代码。
code
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long ll;
const int MAXN = 1e5 + 5;
const int INF = 1e9;
int vis[30], sg[30];
void init()
{
sg[0] = 0;
for(int i = 0; i < 30; i++)
{
memset(vis, 0, sizeof vis);
for(int j = 1; j < i; j++)
{
vis[sg[j] ^ sg[i - j]] = 1;
}
for(int j = 0; j < i; j++) vis[sg[j]] = 1;
for(int j = 0; ; j++)
{
if(!vis[j])
{
sg[i] = j;
printf("sg[%d]:%d\n", i, j);
break;
}
}
}
}
int main()
{
//init();
int T;
scanf("%d", &T);
while(T--)
{
int n;
scanf("%d", &n);
int ans = 0;
while(n--)
{
int x;
scanf("%d", &x);
if(x % 4 == 3) x++;
else if(x % 4 == 0) x--;
ans ^= x;
}
if(ans) puts("Alice");
else puts("Bob");
}
return 0;
}
hdu3595
题意
一共有n个游戏,每一个游戏有两堆石子,一次移动可以从大的那堆石子里拿小的那堆石子的整数倍的石子。只要是可以操作的游戏都要进行操作,不能进行操作的人负。
分析
Every-SG游戏,对于Every-SG游戏先手必胜当且仅当单一游戏中最大的step为奇数,通过dfs找到必败态和必胜态的转移,对于必胜态,尽可能的慢结束游戏,对于必败态尽可能快的结束游戏。
code
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int INF = 1e9;
const int MAXN = 1e3 + 10;
int dp[MAXN][MAXN];
int dfs(int p, int q)
{
if(p > q) swap(p, q);
if(!p) return dp[p][q] = 0;
int k = q / p, tp = q % p, tq = p;
int flag = dfs(tp, tq);
if(k == 1)
{
dp[p][q] = dp[tp][tq] + 1;
return flag ^ 1;
}
else
{
if(!flag) dp[p][q] = dp[tp][tq] + 1;
else dp[p][q] = dp[tp][tq] + 2; // 后面存在一个不是终止态的必败态,这样至少会增加2步。
return 1;
}
}
int main()
{
int N;
memset(dp, -1, sizeof dp);
while(~scanf("%d", &N))
{
int ans = 0;
while(N--)
{
int p, q;
scanf("%d%d", &p, &q);
dfs(p, q);
ans = max(ans, dp[min(p, q)][max(p, q)]);
}
puts((ans & 1) ? "MM" : "GG");
}
return 0;
}
poj3710
题意
- 有 N个局部联通的图。
- Harry 和 Sally轮流从图中删边,删去一条边后,不与根节点相连的部分将被移走。Sally为先手。
- 图是通过从基础树中加一些边得到的。
- 所有形成的环保证不共用边,且只与基础树有一个公共点。
- 谁无法移动谁输。
分析
树的删边游戏,参见论文。
参考代码
code
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
typedef long long ll;
const int INF = 1e9;
const int MAXN = 1e3 + 10;
int next[MAXN], head[MAXN], to[MAXN]; // 前向星
int vis[MAXN]; // 标记数组
// v[i]: 这里就解决了冲突,因为每添加一条边,其实是加入两条边,但是题目本身会存在重边的情况,注意到cnt初始化为1,第一条边是从2开始的,
// 这样每经过一条边,会把相应的v[i]和v[i^1]置为1,正好使得每条边只会被访问一次而不和题目的重边冲突。
int v[MAXN];
int w[MAXN]; // 标记环
int s[MAXN]; // 栈
int cnt, top;
int add(int u, int v)
{
to[++cnt] = v;
next[cnt] = head[u];
head[u] = cnt;
}
int dfs(int x)
{
vis[x] = 1;
s[++top] = x;
int ans = 0;
for(int i = head[x]; i; i = next[i])
{
if(!v[i])
{
v[i] = 1; v[i ^ 1] = 1;
int tmp = 0;
if(!vis[to[i]]) tmp = dfs(to[i]) + 1;
else
{
int q = s[top--];
while(q != to[i])
{
w[q] = 1;
q = s[top--];
}
top++;
return 1;
}
if(w[to[i]]) ans ^= (tmp & 1); // 本来要判断环的奇偶性,回溯的时候是0,1交替,010101...
else ans ^= tmp;
}
}
return ans;
}
int main()
{
int n;
while(~scanf("%d", &n))
{
int ans = 0;
while(n--)
{
memset(next, 0, sizeof next);
memset(head, 0, sizeof head);
memset(vis, 0, sizeof vis);
memset(v, 0, sizeof v);
memset(w, 0, sizeof w);
int m, k; cnt = 1; top = 0;
scanf("%d%d", &m, &k);
for(int i = 0; i < k; i++)
{
int x, y;
scanf("%d%d", &x, &y);
add(x, y);
add(y, x);
}
ans ^= dfs(1);
}
if(ans) puts("Sally");
else puts("Harry");
}
return 0;
}
Nim 博弈和 sg 函数的更多相关文章
- Nim 游戏、SG 函数、游戏的和
Nim游戏 Nim游戏定义 Nim游戏是组合游戏(Combinatorial Games)的一种,准确来说,属于“Impartial Combinatorial Games”(以下简称ICG).满足以 ...
- [您有新的未分配科技点]博弈论入门:被博弈论支配的恐惧(Nim游戏,SG函数)
今天初步学习了一下博弈论……感觉真的是好精妙啊……希望这篇博客可以帮助到和我一样刚学习博弈论的同学们. 博弈论,又被称为对策论,被用于考虑游戏中个体的预测行为和实际行为,并研究他们的应用策略.(其实这 ...
- Nim游戏与SG函数 ——博弈论小结
写这篇博客之前,花了许久时间来搞这个SG函数,倒是各路大神的论文看的多,却到底没几个看懂的.还好网上一些大牛博客还是性价比相当高的,多少理解了些,也自己通过做一些题加深了下了解. 既然是博弈,经典的N ...
- 数学:Nim游戏和SG函数
有若干堆石子,两人轮流从中取石子,取走最后一个石子的人为胜利者 以下的性质是显然的 .无法移动的状态是必败态 .可以移动到必败态的局面一定是非必败态 .在必败态做所有操作的结果都是非必败态 在普通Ni ...
- Nowcoder 挑战赛23 B 游戏 ( NIM博弈、SG函数打表 )
题目链接 题意 : 中文题.点链接 分析 : 前置技能是 SG 函数.NIM博弈变形 每次可取石子是约数的情况下.那么就要打出 SG 函数 才可以去通过异或操作判断一个局面的胜负 打 SG 函数的时候 ...
- 博弈论(nim游戏,SG函数)
说到自己,就是个笑话.思考问题从不清晰,sg函数的问题证明方法就在眼前可却要弃掉.不过自己理解的也并不透彻,做题也不太行.耳边时不时会想起alf的:"行不行!" 基本的小概念 这里 ...
- 【BZOJ1299】巧克力棒(Nim游戏,SG函数)
题意:TBL和X用巧克力棒玩游戏.每次一人可以从盒子里取出若干条巧克力棒,或是将一根取出的巧克力棒吃掉正整数长度. TBL先手两人轮流,无法操作的人输. 他们以最佳策略一共进行了10轮(每次一盒).你 ...
- hihoCoder hiho一下 第四十六周 博弈游戏·Nim游戏·三( sg函数 )
题意: 给出几堆石子数量,每次可以取走一堆中任意数量的石头,也可以将一堆分成两堆,而不取.最后取走者胜. 思路: 先规矩地计算出sg值,再对每个数量查SG值就可以了.最后求异或和.和不为0的就是必赢. ...
- 博弈论初步(SG函数)
讲解见此博客https://blog.csdn.net/strangedbly/article/details/51137432 理解Nim博弈,基于Nim博弈理解SG函数的含义和作用. 学习求解SG ...
随机推荐
- 使用RandomAccessFile类对文件进行读写
1. RandomAccessFile类简介 前面一篇随笔<File类遍历目录及文件>中有说到,File类只能用于表示文件或目录的名称.大小等信息,而不能用于文件内容的访问.而当需要访 ...
- 在mysql 5.6的环境下修改生产环境的表结构(在线ddl) ----工具pt-osc
随着需求的变化越来越快,在线修改表结构变得越来越需要. 在mysql5.6以前,mysql的修改表结构操作会锁表,这样就会造成开发人员或者DBA修改表结构必须要等到凌晨流量谷值或者停服修改.这样必定会 ...
- 关于css禁止文本复制属性
最近在做DHTMLX框架替换,新框架dhx的grid是不能选中内容复制的 虽然相对来说是安全些的,但是客户体验度一定会大打折扣 网页上禁止复制主要靠JavaScript来实现.<BODY onc ...
- 用eclipes 添加jboss tools中的hibernate tool进行反向工程生成数据库对应的BOJO(Javabean)
用eclipes 添加jboss tools中的hibernate tool进行反向工程生成数据库对应的BOJO(Javabean) 安装: 在help中eclise marksplace中查询JBo ...
- 《分布式Java应用之基础与实践》读书笔记一
分布式Java应用的体系结构知识简单分为: 网络通信:包括协议和IO 消息方式的系统间通信:包括基于Java包.基于开源框架.性能角度 远程调用方式的系统间通信:包括基于Java包.基于开源框架.性能 ...
- Vim安装YouCompletMe插件。
1.Centos7.0自带含有支持python2.x的vim.(:version 后看python+则支持,python-则不支持)若不支持,卸载vim后源码编译安装. yum install pyt ...
- 蓝桥杯-组素数-java
/* (程序头部注释开始) * 程序的版权和版本声明部分 * Copyright (c) 2016, 广州科技贸易职业学院信息工程系学生 * All rights reserved. * 文件名称: ...
- crontab定时任务不执行的原因
1.重启crontab若是遇见"You (cloudlogin) are not allowed to use this program (crontab) ...
- PHP学习笔记-1
PHP基本语法 php脚本可以放在文档的任意位置: php脚本以<? php开始,以?>结束: php文件通常包括Html标签和一些php脚本代码: 举个栗子: <!DOCTYPE ...
- Struts2之 OGNL表达式和值栈
技术分析之OGNL表达式概述(了解) 1. OGNL是Object Graphic Navigation Language(对象图导航语言)的缩写 * 所谓对象图,即以任意 ...