大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。
Jetbrains全系列IDE稳定放心使用
每次看到博弈论的题目就很脑阔疼
- 平衡状态,又称作奇异局势。当面对这个局势时则会失败。
- 任意非平衡态经过一次操作可以变为平衡态。
- 先手能够在初始为非平衡的游戏中取胜,后手能够在初始为平衡的游戏中取胜。
一、 巴仕博弈(Bash Game)1堆
-
题目 HDU1846
有一堆物品,两个人轮流从这堆物品中取物,规定每次至少取一个,最多取m个。最后取光者得胜。
-
结论
- 若 n = ( m + 1 ) ∗ r n = (m+1)*r n=(m+1)∗r,先手必败
- 若 n = ( m + 1 ) ∗ r + s n=(m+1)*r+s n=(m+1)∗r+s, ( 1 ≤ s ≤ m ) (1≤s≤m) (1≤s≤m),先手必胜
- 分析
-
(1)如果 n = m + 1 n=m+1 n=m+1
由于一次最多只能取m个,所以,无论先手拿走多少个,后手都能够一次拿走剩余的物品,后者取胜。必败态
-
(2)如果 n = ( m + 1 ) ∗ r + s n=(m+1)*r+s n=(m+1)∗r+s,(r为任意自然数, 1 ≤ s ≤ m 1≤s≤m 1≤s≤m)
先手先拿走s个物品,如果后手拿走k(≤m)个,那么先手再拿走 m + 1 − k m+1-k m+1−k个,结果剩下 ( m + 1 ) ( r − 1 ) (m+1)(r-1) (m+1)(r−1)个,以后保持这样的取法:给对手留下(m+1)的倍数,就能最后获胜。必胜局
- 模板
int Bash_Game(int n,int m)//是否先手有必赢策略
{
if (n%(m+1)!=0) return 1;
return 0;
}
- 变式
- 两个人轮流报数,每次至少报一个,最多报十个,谁能报到100者胜。(<=>从一堆100个石子中取石子,最后取完的胜)
二、威佐夫博弈(Wythoff Game)2堆
-
题目
有2堆物品,两个人轮流从某一堆或同时从两堆中取同样多的物品,规定每次至少取一个,多者不限,最后取光者得胜
-
结论
-
用 ( a [ k ] , b [ k ] ) (a[k],b[k]) (a[k],b[k]) 表示两堆物品的数量,并称其为局势。其中(a[k] ≤ b[k] ,k=0,1,2,…,n)。
-
必败态称为 奇异局势
-
奇异局势公式 :
a [ k ] = [ k ∗ ( 1 + 5 ) 2 ] , b [ k ] = a [ k ] + k 。 ( k = 0 , 1 , 2…… , [ ] 表 示 取 整 ) a[k]=[k*\frac{(1+\sqrt5)}{2}],b[k]=a[k]+k。(k=0,1,2……,[ ]表示取整) a[k]=[k∗2(1+5)],b[k]=a[k]+k。(k=0,1,2......,[]表示取整) -
对于非奇异局势,先手必胜,对于奇异局势,先手必败。
- 分析
-
奇异局势的性质:
(1)任何自然数都包含且仅包含在一个奇异局势中。
(2)任意操作都可以使奇异局势变为非奇异局势。
(3)必有一种操作可以使非奇异局势变为奇异局势。
- 模板
//威佐夫博弈模板
#include <stdio.h>
#include <math.h>
const double Gsr=(1+sqrt(5.0))/2;
int main()
{
int a,b;
while(~scanf("%d%d",&a,&b))
{
if(a>b)
swap(a,b);
if(a == (int)(Gsr*(b-a))) //奇异局势,先拿者输 k = b - a
puts("First Lose");
else
puts("First Win");
}
return 0;
}
- 变式
- “皇后登山”游戏,在空的围棋棋盘上放一个棋子,该棋子每次只能向上或向右或沿对角线向右上方向移动(相似国际象棋),可以移动任意格,但不能不移动,两人轮流移动棋子,先将棋子移动到右上角者赢,问先移棋者的必胜策略。(在两堆中取石子,两堆的数量分别为x,y方向上距离右上角点的长度。)
三、尼姆博奕(Nimm Game) N堆
-
题目
有n堆物品,两个人轮流从某一堆取物,规定每次至少取一个,多者不限(或者最多m个,此时只需把每堆数量%m+1后,同样处理),最后取光者得胜。
-
结论
- 每一堆数量为 a i a_i ai,设H = a 1 a_1 a1 ^ a 2 a_2 a2 ^ … ^ a i a_i ai ^ … ^ a n a_n an
- 若 H = 0 H=0 H=0,先手必败
- 若 H ! = 0 H !=0 H!=0,先手必胜
- 模板
int Nimm_Game(int n)//假设n个数存在数组f[]中,有必胜策略返回1
{
int flag=0;
for(int i=1;i<=n;i++)
flag^=f[i];
if(flag) return 1;
return 0;
}
- 拓展
(1)Moore’s Nimk
-
题目:有N堆石子,其中第i堆有 P i P_i Pi颗石子,每次可以从最多K堆中选出若干石子去掉,每次至少取一个。两人轮流取石,谁不能继续取谁就输了。
-
分析:
- 1、K=1,为Nim问题。
- 2、K>1,把 P 1 P_1 P1~ P n P_n Pn这n个数,转成二进制,然后每位分别相加,每位最后结果mod (K+1)。如果每一位结果都是0,则先手必败,否则是先手必胜。
-
证明
1.全为0的局面一定是必败态。
2.任何一个P状态,经过一次操作以后必然会到达N状态:在某一次移动中,至少有一堆被改变,也就是说至少有一个二进制位被改变。由于最多只能改变k堆石子,所以对于任何一个二进制位,1的个数至多改变k。而由于原先的总数为k+1的整数倍,所以改变之后必然不可能是k+1的整数倍。故在P状态下一次操作的结果必然是N状态。
3.任何N状态,总有一种操作使其变化成P状态。从高位到低位考虑所有的二进制位。假设用了某种方法,改变了m堆,使i为之前的所有位都回归到k+1的整数倍。现在要证明总有一种方法让第i位也恢复到k+1的整数倍。
有一个比较显然的性质,对于那些已经改变的m堆,当前位可以自由选择1或0.
设除去已经更改的m堆,剩下堆i位上1的总和为sum
分类讨论:
(1)sum<=k-m,此时可以将这些堆上的1全部拿掉,然后让那m堆得i位全部置成0.
(2)sum>k-m 此时我们在之前改变的m堆中选择k+1-sum堆,将他们的第i位设置成1。剩下的设置成0.由于k+1-sum<k+1-(k-m)<m+1,也就是说k+1-sum<=m,故这是可以达到的。
(2)楼梯Nim(staircase nim)POJ 1704
- 题目:每层有若干个石子,每次可以选择任意层的任意个石子将其移动到该层的下一层。最后不能操作的人输。
- 分析:把所有奇数阶梯看成N堆石子做nim。把石子从奇数堆移动到偶数堆可以理解为拿走石子,就相当于几个奇数堆的石子在做Nim。
- 策略
假设我们是先手,所给的阶梯石子状态的奇数堆做Nim先手能必胜.我就按照能赢的步骤将奇数堆的石子移动到偶数堆.
如果对手也是移动奇数堆,我们继续移动奇数堆.
如果对手将偶数堆的石子移动到了奇数堆.那么我们紧接着将对手所移动的这么多石子从那个奇数堆移动到下面的偶数堆.两次操作后.相当于偶数堆的石子向下移动了几个。而奇数堆依然是原来的样子,即为必胜的状态。
就算后手一直在移动偶数堆的石子到奇数堆,我们就一直跟着他将石子继续往下移,保持奇数堆不变。我可以跟着后手把偶数堆的石子最终移动到0,然后对手就不能移动这些石子了.
所以整个过程.将偶数堆移动到奇数堆不会影响奇数堆做Nim博弈的过程…整个过程可以抽象为奇数堆的Nim博弈.
为什么是只对奇数堆做Nim就可以而不是偶数堆呢?因为如果是对偶数堆做Nim,对手移动奇数堆的石子到偶数堆,我们跟着移动这些石子到下一个奇数堆。那么最后是对手把这些石子移动到了0,我们不能继续跟着移动,就只能去破坏原有的Nim而导致胜负关系的不确定。所以只要对奇数堆做Nim判断即可知道胜负情况.
(3)反nim游戏(anti-nim) bzoj 1022
-
题目:正常的nim游戏是取走最后一颗的人获胜,而反nim游戏是取走最后一颗的人输。
-
分析:
一个状态为必胜态,当且仅当:
1)所有堆的石子个数为1,且NIM_sum(异或和)=0
2)至少有一堆的石子个数大于1,且 NIM_sum≠0 -
证明
(4)新Nim游戏 BZOJ3105- 题目:在第一个回合中,第一个游戏者可以直接拿走若干个整堆的火柴。可以一堆都不拿,但不可以全部拿走。第二回合也一样,第二个游戏者也有这样一次机会。从第三个回合(又轮到第一个游戏者)开始,规则和Nim游戏一样。
如果你先拿,怎样才能保证获胜?如果可以获胜的话,还要让第一回合拿的火柴总数尽量小。 - 分析:
为使后手必败,先手留给后手的必然是若干线性无关的数字,否则后手可以留下一个异或和为零的非空子集使得先手必败,故问题转化为拿走和最小的数字使得留下的数线性无关,即留下和最大的线性基,这样拿走的数量显然最少,找到和最大的线性基只需贪心的把数字从大到小加入到基中即可(证明需用到拟阵) - 模板
- 题目:在第一个回合中,第一个游戏者可以直接拿走若干个整堆的火柴。可以一堆都不拿,但不可以全部拿走。第二回合也一样,第二个游戏者也有这样一次机会。从第三个回合(又轮到第一个游戏者)开始,规则和Nim游戏一样。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll sum;
int k,num[520],d[520];
inline int read()
{
int x=0,f=1; char ch=getchar();
while(ch<'0'||ch>'9') {
if(ch=='-') f=-1; ch=getchar();}
while(ch>='0'&&ch<='9') {
x=x*10+ch-'0'; ch=getchar();}
return x*f;
}
int Insert(int k)
{
for(int i=31;i>=0;--i)
{
if(k&(1<<i))
{
if(!d[i]) {
d[i]=k; return 1;}
else k^=d[i];
}
}
return 0;
}
bool cmp(int a,int b) {
return a>b;}
int main()
{
k=read();sum=0;
for(int i=1;i<=k;++i) num[i]=read();
sort(num+1,num+1+k,cmp);
for(int i=1;i<=k;++i) if(!Insert(num[i])) sum+=num[i]*1ll;
printf("%lld\n",sum);
return 0;
}
四、斐波那契博弈(Fibonacci Game)1堆
-
题目 HDU 2516
有1堆石子,两人轮流取。先取者第1次可以取任意多个,但不能全部取完。以后每次取的石子数不能超过上次取子数的2倍。取完者胜。
-
结论
- 2,3,5,8,13为必败点,根据找最近必败点的规律,我们可以发现若不能直接使得对方陷入必败点的话,就需要开始计算与最近必败点的差值来判断,如此推算,我们可以得出每个必败点刚好是前两个必败点的和,即斐波那契数。
- 若n为斐波那契数,则先手必败,否则先手必胜。
五、固定多个数目取石子
-
题目
有1堆石子,两人轮流取。每次可取1、2、4颗。取完者胜。
-
结论
- 若 n % 3 = = 0 n \% 3==0 n%3==0,先手必胜,否则先手必败
-
分析
当先手取完本轮石子后,剩下的石子为3的倍数(3*n)
① n = 1时,即先手取完后只剩下3颗,那么无论后手怎么取(1或2),先手下次取都会取到最后一颗(1或2),先手必胜。
②n >1时,接下来一次,当Bob取完后(1或2或4),剩下的石子数量总可以表示为: 3 ∗ k + 1 或 3 ∗ k + 2 ( k > = 0 ) 3*k+1 或 3*k + 2(k >= 0) 3∗k+1或3∗k+2(k>=0),那么此时先手可以将剩下的石子数重新变为3的倍数,如此递推下去,最终剩下石子数量变为3,先手必胜。
六、约数博弈
-
题目
游戏初始状态包含1-n, 这n个正整数。甲乙两个人轮流玩这个游戏,每轮游戏中,游戏者任意选择一个还存在的数,然后删掉它和它所有的约数。第一个删掉所有数的人获胜。
-
结论
- 先手必胜
-
分析
反证法:假设后手B有必胜策略,而先手A第一次取数1,B取了一个数x是必胜策略,然而A完全可以第一次取x(同时也必取了1)是必胜策略。故B必没有必胜策略。【1是所有数的约数】
-
变式
- 考虑一个新的规则“不准写数字1”。
- 如果加上这个新规则,先手必胜
- 证明:如果在新规则下后写者必胜,则原游戏中的先写者写下数字1,然后他就变成了新规则下的后写者。
七、约数和倍数博弈
-
题目
游戏初始状态包含2-n, 这n-1个正整数。甲乙两个人轮流玩这个游戏,每轮游戏中,游戏者任意选择一个还存在的数,然后删掉它和它所有的约数、倍数。第一个删掉所有数的人获胜。
-
结论
- 先手必败
Tips:
-
双方共用状态(合法的决策完全相同)的对弈游戏,称为ICG游戏,至少有一方存在必胜策略。
-
棋局的任一状态只有两种,面对这个棋局的人要么必胜要么必败。
-
Strategy-stealing分析法:
- 如果一个状态是必胜态,那至少有一种走法能走成一个必败态留给对方。
- 如果一个状态是必败态,那它怎么走都只能走到必胜态。
- 运用这样的关系,我们可以自底向上推出初始状态是必胜还是必败。
-
下面的Chomp博弈就是典型例子。
-
对于其它一些非ICG游戏,我们也可以用类似的方法证明后手不可能有必胜策略(但在这里并不能说明先手一定必胜)。比如对于井字棋游戏,假设后手有必胜策略,那先手就随便走一步,以后就装成是后手来应对。如果在哪一步需要先手在已经下过子的地方落子,他就再随便走一步就是了。这种证明方法成立的前提就是,多走一步肯定不是坏事。事实上,对于所有这种“多走一步肯定不是坏事”的且决策对称的游戏,我们都可以证明后手是没有必胜策略的。
八、Chomp博弈(巧克力游戏)
-
题目
有一个n * m的棋盘,每次可以取走一个方格并拿掉它右边和上面的所有方格。拿掉左下角的格子(1,1)者输。
例如,下图是8*3的棋盘中拿掉(6,2)和(2,3)后的状态。
-
结论
- 除了1*1的棋盘,先手必败
- 对于其他大小的棋盘,先手必胜。
- 分析
- 若后手必胜,使得无论先手第一次取哪个石子,后手都能获得最后的胜利。
- 现在假设先手取最右上角的石子(n,m),接下来后手通过某种取法使得自己进入必胜的局面。
- 但事实上,(n,m)是初始态,先手在第一次取的时候就可以和后手这次取的一样,进入必胜局面了,与假设矛盾。
其他题型(还没打开看,不知道是不是)
POJ1740A New Stone Game
MIPT 100 Nim Game – who is the winner?
POJ 1704 Georgia and Bob
翻硬币游戏:这类题目比较复杂,一般打表找规律。
图的删边游戏
约数倍数选卡片
Take-and-Break Game
( n堆石子,每次可以取走一堆石子,然后放入两堆规模更小的石子(可以为0).最后不能操作的人输。
这种题貌似需要用SG函数来解。
f[i]表示还剩一堆i颗石子堆得状态,f[i][j]表示两堆的状态,然后依次类推。
根据SG函数的定义有f[i]=min{n∈N|n!=f(p,q) i>p>=0&&i>q>=0}
然后递推求得子游戏的任意状态。)
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/181528.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...