巴什博奕(Bash Game)
题意:
只有一堆n个物品,两个人轮流从这堆物品中取物,规定每次至少取一个,最多取m个。最后取光者得胜。
思路: 1.如果 n = m+1,由于一次最多只能取m个,所以无论先手取着拿走多少个,后手都能一次取完。那么就是后者胜利。 2.所以我们可以得到取胜的结论: n = (m+1)r + s; 意思就是我们先手要先拿走s个,然后不论后手怎么去取k个,我们都取m+1 - k个,如此保证必然能够获胜。 3.总结:就是给对手留下(m+1)的倍数
威佐夫博奕(Wythoff Game)
题意:
有两堆各若干个物品,两个人轮流从某一堆或同时从两堆中取同样多的物品,规定每次至少取一个,多者不限,最后取光者得胜。
思路:本题我们可以用一(ak,bk)来表示当前两堆物体的状态。 1.首先我们要理解一个概念,奇异状态,当然也可以叫做失败态。 比如这个题目中,我们很容易得到(0,0)是奇异状态。 2.那么我们能否得到所有的奇异状态呢?我们可以从(0,0)开始往后推得到每一个奇异状态
从第0个失败态开始(0,0),(1,2),(3,5),(4,7),(6,10),(8,13)
对于本题有以下规律: 1.第i个奇异状态之间的两个数的差值为 i; 2.ak表示奇异状态中的第一个数,bk表示奇异状态中的第二个数。那么ak是前面奇异状态中没有出现过的最小的整数。bk = ak + i; 3.每个数仅包括在一个奇异状态中。 每个奇异状态都可以转到一个非奇异状态 每个非奇异状态都可以转到一个奇异状态 4.每个奇异状态中两个数的差值 * 1.618向下取整就是这个奇异状态的第一个数。
本题解法:所以对于本题给两堆石子,求先手输赢,我们就可以根据当前给的着组数是不是奇异状态来判断先手是否会赢。 扩展:如果还要求假设先手赢,先手第一次怎么取石子,可以分为同时取和在一堆取,主要是取后的石子为奇异状态。 本题AC代码:
#include<bits/stdc++.h>
using namespace std;
int main(){
int a, b, t;
scanf("%d %d", &a, &b);
if (a>b) swap(a, b);
t=floor((b-a) * (1+sqrt(5))/2);
if (a==t)
printf("先手lose");
else
printf("先手win");
return 0;
}
尼姆博奕(Nimm Game)
题意:
有三堆各若干个物品,两个人轮流从某一堆取任意多的物品,规定每次至少取一个,多者不限,最后取光者得胜。
思路: 1.我们可以用(a,b,c)表示某种局势,首先(0,0,0)显然是一个奇异局势。 2.那么第二种奇异局势是什么呢?(0,n,n)。在这种状态下我们只需要拿走跟对手一样多的物品,最后都会到达(0,0,0)的状态,让对手面对奇异局势。 3.仔细分析一下,(1,2,3)也是一种奇异局势,无论对手怎么取,都将会变成(0,n,n)的情景。
对于每一个奇异局势,都有异或和为0。 你要是问为什么?我们老祖宗推出来的,就像你问为什么地球是圆的一样。记住即可。
下面我们简单说一下PN状态这两个概念。一遍后续学习SG函数。
N点:如果在双方都采用最佳策略,如果当前点的玩家最终获胜。那么这个点就是N点。 P点:如果在双方都采用最佳策略,当前这个点最候会导致失败,就是P点。
我们想赢的话,就是每次往P点走,把失败留给敌人。