ACM博弈学习小结

本文总结了ACM中的博弈问题,强调了博弈题目的特点和解决思路。从理解局面的重要性到深入探讨SG值的概念,解释了如何通过递归定义找到胜负状态。介绍了胜态与败态的转换规则,并以Nim游戏为例说明了异或运算在确定游戏胜负中的应用。此外,还讨论了平局的情况以及在博弈策略中的考量。文章通过实际题目展示了如何运用SG打表寻找规律,提供了博弈解题技巧。
摘要由CSDN通过智能技术生成

一、心得体会

1.ACM博弈题,不会的时候觉得难于上青天,会的时候觉得没有比博弈更水的题了;

博弈题看到的第一眼觉得是难题,代码敲完顿觉水题。你可能花半个小时去找规律,然后仅花2分钟敲代码。

2.博弈是单人游戏,也可以说是自己跟自己玩,因为“双方都做出最优决策”这一点限制了,最后的结果不取决

于你是谁,不取决于你的智商,只取决于你面对的局面

3.局面,这是博弈里面最最最重要的东西!!!(所谓SG也是指这一局面的SG),博弈是一种不公平的游戏

因为游戏开始的时候已经结束了,影响你胜负的就是你所面对的局面,因为双方采取最优策略

故而局面必然会以双方当前对自己最优的路径走下去,所以结局已经确定了

4.当你面对一个局面的时候如何做出最优的决策呢?你一定是走到了最后一步才确定了胜负,所以当前的局面

往往需要从最终的局面逆推而来(也就是从一个已知胜负的局面一步步推导其他的局面,有了这样的思想,SG

也就不那么难理解了)

5.关于SG:

入门了博弈的人都知道,博弈里面常常用到一个重要的概念 -- SG。但是SG是什么?你去百度的话会有非常专业的解答,

但是那些所谓的专业绝对让人看的头疼。这里说说我所理解的博弈里面的SG(仅限博弈)

挑程里是这样解释SG值的:

          任意一步所能转移到的子局面的SG值以外最小非负整数

仔细体会一下这句话,你会发现,这里对SG值的定义是递归定义的!

当前局面的SG是什么呢?请先去找当前局面的子局面的SG值。

显然,递归是有一个边界的,SG是一种递归,那么它也是有边界的,

不难发现,它的边界是没有子局面的局面(也就无法再转移的局面)

什么样的局面没有子局面呢,也就是胜负已定的局面。在第4点说到,

当前局面的最优策略是从胜负已定的最终局面逆推来的,这里的SG其实也是

说了这些,那么SG到底是什么呢?

联想当年学习递归的一个例子:

f(n)  =   1         , n = 1

            f(n-1) +1  ,n > 1

这样一个函数是我们学习递归时的经典例子,你说这里的F到底是什么?其实它不过是一个函数而已。

SG也是一样,它只是一个函数而已,函数这个词翻译成英语再翻译成中文,就成了“功能、作用”

那么SG的作用是什么呢?

举一个最简单的例子:

有一堆石头数量为n,两个人轮流从石堆拿{a1,a2,a3,......,ak}个石头,先取完所有石头者胜。

根据前面说的,首先找胜负已定的局面,当n=0的时候,石头被拿完了,败态

那么sg[0] = 0表示面对0个石头的局面者败,然后根据sg的定义,我们可以求出其他局面的sg值

(为了使每种局面确保有可以转移的子局面,我们假设{a1,a2,a3......,ak}里面一定有1,例如假设没有1的话

,假设为{5,6,7}那么局面4没有可以转移的子局面,这样会出现平局的情况,我们后面再说平局)

这样可以求出所有局面的sg值,然后sg的作用出来了~

我们发现,若sg[x] = 0,那么x是败态,这其中很神奇,鶸也说不清楚,只说一下胜态败态的转移

(其实光理解的话可能还是不知道什么是SG,但是看了后面的题目就能理解了并知道怎么用SG找到游戏的胜态败态了)

6.胜态与败态:

之前说了,博弈里面,游戏开始的时候已经结束了,影响你胜负的就是你所面对的局面。

也就是说,这个局面觉得了你的胜负,我们称能让你走向胜利的局面称为胜态,也是必胜态,专业术语也叫P态(积极的英语单词怎么写?)

称让你走向失败的状态称为败态,也是必败态,专业也叫N态(消极的英语单词鶸也不会拼。。。)

有一个很显然的规律:

只要当前状态可以转移到的状态中有一个是败态,那么当前状态就是胜态。

如果当前状态可以转移到的所有状态都是胜态,那么当前状态就是败态。

这两句话互为逆否命题,一眼就看出是对的就不解释了。

可以胜态败态的角度去理解下SG。

7.Nim游戏:

关于这个Nim游戏,百度的话又是一大堆乱七八糟看不下去的东西,

它的最原始的版本大概是说有N堆石头,{a1,a2,a3......,an}表示每堆的数量,两个人轮流选一个石堆拿若干石头(不能不拿),

如果轮到某个人时所有的石子堆都已经被拿空了,则判负。

这个游戏有个非常完美的结论:

令   s  =  a1^a2^a3....^an(^符号表示异或运算)

若 s = 0,则此局面为败态,否则为胜态

对于上面的式子,我们不难发现,当你从一个石堆拿走一些石头(即改变一个ai),一定会发生胜态和败态的转变

胜态一定会转移成败态,败态也一定有策略转移成胜态

当这个结论与SG结合,神奇的事发生

我们发现sg异或和为0的状态也是败态,否则胜态。

另外,很多游戏都可以转变为Nim的形式,例如POJ 1704(挑程上有讲解)

8.关于平局:

我们发现,一个必胜态的获得,必然是因为它可以转移到一个败态,那么是不是说相比于平局我们更倾向于败态呢?

如果有更多的败态,理论上可以转移出更多的胜态,但是孩子别太天真了啊~

博弈将“对敌人的仁慈就是对自己的残忍”这句话发挥的淋漓尽致,当你选择败态的时候,对方却不会傻傻按照你的想法给你转移胜态的

该你输的时候你还是得输,所以,在博弈里的决策,一定要是对自己最有利对对手最不利的策略才是最优策略,、

也就是说,如果实在不能赢,你一定宁可平局,也不要选择败态。例如今年HDU 多校题5754 里面马的情况

9.当初关于博弈看了很多但是都只是似懂非懂,只有做多了题才有更多的·体会

二、博弈做题技巧

做了个专题:点击打开博弈专题

题目其实好多都是做过的原题,不过以前都是自己找规律的,这次就是用SG打表找规律,通过这些题目也算是知道怎么使用SG找规律了

其中的题目大多都是打表找规律,不过也有一些有趣的题目

PS:题目选自kuangbin 的博弈分类:点击打开链接(难度的话,后面的题都蛮简单,前面的题稍难)

1.打表找规律题:
输入n,从1开始,每次乘以2~9的数,谁最先达到n谁胜
直接上代码,其中solve()函数是打表的过程,找完规律之后直接解决不需要solve,不过为了记录自己的思路,打表的代码也保留了
#include<iostream>
#include<cstdio>
#include<cstring>
#include<set>
#define mem(a,x) memset(a,x,sizeof(a))
using namespace std;
typedef long long ll;
/*
	败态: 
	10 - 18 
	163 - 324
	2917 - 5832
	综上:
	败态:
	(9*18^i,18*18^i]
	i从0开始 
*/
const int N = 100000; 
int sg[N+4];
void solve()
{
	sg[1] = 0; 
	for (int i = 2;i <= N;++i)
	{
		set<int>s;
		for (int j = 2;j <= 9;++j)
		{
			int to = i/j;
			if (i%j)to++;
			s.insert(sg[to]); 
		}
		int g = 0;
		while (s.count(g)) ++g;
		sg[i] = g;
	}
	for (int i = 2000;i <= 9000;++i) 
	{
		cout<<i<<" "<<sg[i]<<endl;
	} 
}
ll l[10],r[10];
void init()
{
	l[0] = 9,r[0] = 18;
	for (int i = 1;i <= 9;++i)
	{
		l[i] = 18LL*l[i-1];
		r[i] = 18LL*r[i-1];
	}
} 
bool loser(ll x)
{
	for (int i = 0;
  • 22
    点赞
  • 62
    收藏
    觉得还不错? 一键收藏
  • 12
    评论
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值