赞
踩
这篇博主要记录了巴什博弈、威佐夫博弈、斐波那契博弈、尼姆博弈与Grundy数(SG函数)等博弈论相关学习笔记。
博弈论题目的主要特点:
在推到几种博弈的前提是你自己必须想:我是先手!!我一定要赢!!拿出自己的最优策略。
以下是几种常见的博弈题型:
一堆n个物品,两名选手轮流从中取出1~m个,最后取光者胜。用一个数字(x)表示一堆物品中剩下的数量。
还剩0个物品是一种必败态。当物品还剩下0个、就是一种必输的局势,被称为必败态。
还剩m+1个物品也是一种必败态。因为如果你最多取m个,留给后手的一定小于或等于m个,所以这也是必败态。
接着我们来讨论物品还剩(m+1+k)的情况:
所以,综上所述:若n%(m+1)==0先手必败、反之先手必胜。
核心代码:
- int n,m;
- cin >> n >> m;
- if(n%(m+1)==0)
- cout << "先手必败!\n";
- else
- cout << "先手必胜!\n";
有两堆各若干个物品,两人轮流从某一堆或同时从两堆中取同样多的物品,每次至少取一个、多的不限。A先手。
我们用(ak,bk)表示两堆物品数量局势,若A面对(0,0),那么A输,这种先手必输的局势,我们称为奇异局势。同样的我们可以得到(0,0)、(1,2)、(3,5)、(4,7)、(6,10)、(8,13)、(9、15)、(11,18),(12,20)等等。我们在这些局势前很容易发现ak是未在前面出现过的最小自然数,又有:bk=ak+k。我们的ak也可以由[k*(√5+1)] / 2。
所以我们先求出差,差值*黄金分割比==最小者后手赢、否则先手赢。
核心代码:
- doublee r = (sqrt(5)+1)/2;
- int d = abs(a-b)*r;
- if(d!=min(a,b)) return ture;
- else return false;
一共n个物品,两人轮流取出1~任意个,但是不能取完,以后每次取的物品都不能超过上一次的2倍,取完者胜。
我们令n代表,还有多少个物品,试着推导一下:
n=2,后手win。先手取一个,后手就能全部取完。
n=3,后手win。先手无论取一个还是两个,后手都可以一次性取完。
n=4,先手win。若先手取一个,后手剩3个,状态转移至n=3,当n=3时,后手先取,先手win。
n=5,后手win。先手取一个,剩余4个,状态转移至n=4,后手先取,后手赢。若先手取两个或者三个,后手可以一下全部取完获胜。
n=6,先手win。先手取一个,剩余5个,状态转移n=5,后手先取,先手赢。
n=7,先手win。先手取两个,状态转移至n=5,后手先取,先手赢。
n=8,后手win。先手取一个,状态转移n=7,后手赢。
等等等等,不再陈述……
我们不难发现,若n是斐波那契数列,后手赢。反之先手赢。
核心代码:
- f[0]=f[1]=1;
- for(int i=0;f[i-1]<n;i++){
- f[i]=f[i-1]+f[i-2];
- if(f[i]==n) return true;
- }
- return false;
有n堆物品,两人轮流取,每次取某堆中不少于一个,最后取完者胜。
要判断游戏的胜负,只需用异或运算就好了。(也不知道哪位神仙发明的如此神奇的算法)。
a1 XOR a2 XOR …… XOR an !=0 先手赢,若==0后手赢。
核心代码:
- int res=0;
- for(int i=0;i<N;i++)
- res ^= A[i];
- if(res!=0) cout << "先手win!\n";
- else cout << "后手win!\n";
有n堆物品,只能按规定集合拿,谁先取完谁获胜!这个东西压轴出场超级神奇!用的好可以解决以上所有问题!
emmm……由于递推过程比较复杂,在这里也不做过多阐述,我感觉套模板就可以了,有兴趣的读者可以前往以下链接:
https://blog.csdn.net/Dog_dream/article/details/80445886 (写的比较详细)
核心代码:
- int n,k,x[MAXN],a[MAXN];
- int grundy[MAXN+1];
- void solve(){
- grundy[0]=0;
- int max_x = *max_element(x,x+n);
- for(int j=1;j<=max_x;j++){
- set<int> s;
- for(int i=0;i<k;i++){
- if(a[i]<=j) s.insert(grundy[j-a[i]]);
- }
- int g=0;
- while(s.count(g)!=0) g++;
- grundy[j]=g;
- }
- int res=0;
- fpr(int i=0;i<n;i++)
- res^=grundy[x[i]];
- if(res!=0) cout << "First win!\n";
- else cout << "Second win!\n";
- }
HDU 2516 取石子游戏 【传送门】
HDU 1527 取石子游戏 【传送门】
HDU 2188 悼念512汶川大地震遇难同胞——选拔志愿者 【传送门】
HDU 1846 Brave Game 【传送门】
HDU 1850 Being a Good Boy in Spring Festival 【传送门】
HDU 2176 取(m堆)石子游戏 【传送门】
HDU 1847 Good Luck in CET-4 Everybody! 【传送门】
HDU 1525 Euclid's Game 【传送门】
HDU 1848 Fibonacci again and again 【传送门】
待解决:
POJ 1082 Calendar Game
HDU 1564 Play a game
HDU 2897 邂逅明下
HDU 3032 Nim or not Nim ?
…………慢慢扩展队列,今天不想一个一个粘贴了……
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。