【算法总结】博弈论学习

学习(复习)博弈已经两天,然而看和思考的题远远不够,没有抓紧时间
学习一个模型最重要的是能够掌握其基本的定理和运用,需要尽可能多的看各类的题。要抓紧时间找题来想,深入的思考,不能懒惰!

基础的博弈理论

zwfymqz的总结
yyb的总结
**两位大佬总结的非常详细了,我就不再赘述了
博弈最重要的是从博弈的本质出发,能够运用和转化模型:
根据N,P状态的定义来寻找性质
多个子游戏的SG抑或起来,那么我们需要化简出最简的子游戏,通过DP,搜索或者打表来求出SG函数
通过两轮后性质的不变来简化模型----两轮后仍具有的相同性质说明这两轮不会影响胜负(比如取模)
二分图博弈的性质要注意:
点不重的二分图博弈:如果起点在所有最大匹配上则先手必胜。
每次删边的二分图博弈:如果能够找到右边的集合,与左边的相邻集合只有起点度数为奇数,则先手必胜

anti-SG

注意不是所有最后一个操作的人输的题目都是anti-SG。要满足:
对于任意一个Anti-SG游戏,如果我们规定当局面中所有的单一游戏的SG值为0时,游戏结束。
(该条件可以弱化为:当局面中所有的单一游戏的SG值为0时,存在一个单一游戏它的SG函数能通过一次操作变为1)

先手必胜当且仅当:
(1)游戏的SG函数不为0且游戏中某个单一游戏的SG函数大于1;
(2)游戏的SG函数为0且游戏中没有单一游戏的SG函数大于1。

例如在取石子(最经典的nim)中,单一游戏SG = 0当且仅当石子数为空,游戏显然结束。
证明看2009 贾志豪的论文《组合游戏略述 ——浅谈SG游戏的若干拓展及变形》

无向图删边游戏:

缩边双:边双里有偶数条边,则SG = 0 , 奇数条边,则SG = 1
然后在树上做删边游戏

例题和好题

lzw’s blog
这上面有很多opentrains上的题,考虑到以后可能会训练,就没有看

anti-SG 例题:树上删边,最后一个删的人输

首先这是满足anti-SG的条件的。因为删边本质是取石子的组合
还要注意在删边游戏中每个子游戏是根下面的儿子,即一个根代表度数个子游戏的组合,而子游戏与根无关

这题需要输出方案,开始想得特别麻烦,以为要自底向上维护删除的方案。然而,从SG的定义考虑,一个点的SG = i意味着它可以转移到 0 − ( S G − 1 ) 0 - (SG - 1) 0(SG1)的所有局面。所以直接dfs即可,一定有解。
按照SJ定理讨论清楚,所有情况
当输出了一组合法方案的时候直接exit(0),这样写最简单。因为输出了多组方案调了一会。

#include
using namespace std;

const int maxn = 1e5 + 10;
struct node{
	int next,to;
}e[maxn * 2];
int head[maxn],cnt,f[maxn],n,m,deg[maxn],sz[maxn],fa[maxn];
vector <int> vec,vec2;

void adde(int x,int y){
	e[++cnt].to = y;
	e[cnt].next = head[x];
	head[x] = cnt;
}
void dfs(int x){
	sz[x] = 1;
	for (int i = head[x] ; i ; i = e[i].next){
		fa[e[i].to] = x;
		dfs(e[i].to);
		f[x] ^= f[e[i].to] + 1;
		sz[x] += sz[e[i].to];
	}
}
void dfs_ans(int x,int SG){
	if ( SG == -1 ){
		printf("%d %d\n",fa[x],x);
		exit(0);
	}
	for (int i = head[x] ; i ; i = e[i].next){
		int cur = (SG ^ f[x] ^ (f[e[i].to] + 1)) - 1;
		if ( cur < f[e[i].to] ){
			dfs_ans(e[i].to,cur);
			return;
		}	
	}
	assert(0);
}
void getans(int SG){
	if ( SG == 0 ){
		if ( vec.size() == 0 ){
			puts("Petr");
			//find
			assert(vec2.size());
			printf("%d %d\n",fa[vec2[0]],vec2[0]);
		}
		else{
			puts("Vasya");
		}
		return;
	}
	if ( vec.size() == 1 ){
		puts("Petr");
		int x = vec[0];
		if ( SG == f[x] + 1 ){
			dfs_ans(x,0);
		}
		else{
			printf("%d %d\n",fa[x],x);
		}
	}
	else if ( vec.size() > 1 ){
		puts("Petr");
		for (auto x : vec2){
			int cur = (SG ^ (f[x] + 1)) - 1;
			if ( cur < f[x] ){
				dfs_ans(x,cur);
				return;
			}
		}
	}
	else puts("Vasya");
}
int main(){
//freopen("i.in","r",stdin);
	scanf("%d %d",&n,&m);
	for (int i = 1 ; i <= m ; i++){
		int x,y;
		scanf("%d %d",&x,&y);
		adde(x,y);
		deg[y]++;
	}
	int SG = 0;
	for (int i = 1 ; i <= n ;i++) if ( !deg[i] ){
	 	for (int x = head[i] ; x ; x = e[x].next){
	 		fa[e[x].to] = i;
	 		dfs(e[x].to);
	 	 	SG ^= f[e[x].to] + 1;
	 	 	if ( f[e[x].to] ) vec.push_back(e[x].to);
	 	 	vec2.push_back(e[x].to);
			//cout<
	 	}
	}
	getans(SG);
}

codeforces 919F. A Game With Numbers

题解
状态数很少,可以直接求bfs
按照0的个数分层,从确定的状态bfs,相当于拓扑排序
一个状态若能转移到P状态则是N状态
若能转移到D状态则是D,或者不能被转移到也是D
只能转移到N则是P

总结:
正确算状态数!
博弈的转态是图,如果有环就是平局,仍然可以类拓扑排序
还没有写,应该在想出后就快速的实现,不应该浮躁的看更多的题

codeforces 1033G. Chip Game

题解
如果a+b确定,每堆石子数显然可以模(a + b)
简单证明
任意一堆>(a + b), 先手拿完后,后手可以使得重复使得%(a + b)不变
经过两轮后的不变性质一般在博弈中可以化简
然后分类讨论
The winner of G′ can always make a move in the game G and hence also wins G.
Let’s break down the single pile games P based on the number of chips modulo a+b:
0≤v′i a≤v′i0).
b≤v′i<2a: If either of the players makes a move, it changes to a zero game. This is thus a fuzzy game (P||0). Note that this interval may be empty.
max(2a,b)≤v′i

总结:
这道题本来不难,但是写了一个多小时,还没有调出来
一开始分类讨论情况掉了最后一种,
并且没有想清楚代码该怎么写,就开始写,这样一定会浪费时间。
调试的时候也应该即时停下来,想清楚再修改,超出规定的时间就不能再调了,不能盲目的浪费时间!

codeforces 1037G. A Game on Strings

题解
枚举一开始选哪个字符,分成的多段字符串
直接看成multi-SG,对于每个子游戏分别计算SG值
注意复杂度计算:
对于每个字符,最多分26层,每层区间总长<=n(区间个数更少),所以这一步是26 * 26 * n的
对于询问直接枚举第一步决策,然后发现包括区间两端的不完整区间其实都是算过的。

总结:
要仔细计算复杂度,自己一定要想清楚,不能还没有想清楚就看题解,这样没有意义!

codeforces 1091H. New Year and the Tricolore Recreation

题解
每个状态看成一个二元组(x,y),每个人可以变成x - k或者y - k
进而发现x和y也是独立的
于是得到2 * n个独立子游戏
计算SG的时候用bitset优化。观察或者打表(我直接看了题解)发现SG最大值<=100,那么维护100个bitset
第i个bitset记录拥有SG为i的后继的状态j有哪些。

code
总结:
要利用游戏独立的性质,拆分成最简的子游戏
猜测SG值不大,然后用bitset优化求SG过程

你可能感兴趣的:(博弈,知识点总结)