概述
#define P(positive) 必胜态
#define N(negative) 必败态
巴什博奕(Bash Game)
有一堆石子n个 , 每次可以取1~m个石子 , 没有石子可取的那方输 , 问第一个取的人的输赢
给对面一个m+1的堆 , 无论对面取多少 , 你都可以取一个数使这堆石子取完
所以说你要设法取一个数使堆剩下 k ( m + 1 ) k(m+1) k(m+1)给对面
int main(){
LL t;sf(t);
while(t--){
LL n,m;sf(n),sf(m);
if(n%(m+1))printf("firstn");//可以把k*(m+1)这个状态给对面
else printf("secondn");//到自己手上的状态是k*(m+1)
}
}
变形(最后取的输) :
只要留一块给对面就赢了,所以判断(n-1)%(m+1)
威佐夫博奕(Wythoff Game)
有两堆各若干个物品,两个人轮流从某一堆或同时从两堆中取同样多的物品,规定每次至少取一个,多者不限,最后取光者得胜。
我们用 ( a [ k ] , b [ k ] ) (a[k],b[k]) (a[k],b[k])表示两堆物品的数量并称其为局势,显然(0,0)为必输局势,这种必输局势我们称为奇异局势。
前几个奇异局势是:(0,0),(1,2),(3,5),(4,7),(6,10),(8,13),(9,15),(11,18),(12,20)
a[k]为前k-1中的a[i]b[i]中未出现的最小非负整数 , b[k]=a[k]+k (a[0]=b[0]=0)
公式 :
a [ k ] = [ k ( 1 + √ 5 ) / 2 ] , b [ k ] = a [ k ] + k a[k] = [k(1+√5)/2] ;, ;b[k]=a[k]+k a[k]=[k(1+√5)/2],b[k]=a[k]+k
性质 :
- 每个自然数只会出现在一个奇异局势1
- 奇异局势在一次操作后变成非奇异局势2
- 非奇异局势可以在一次操作后变成奇异局势3
奇异局势判断 :
直接判断小的那堆能不能写成上面a的公式 ( k = b − a ) (k=b-a) (k=b−a)
int main(){
int a,b;
while(scanf("%d%d",&a,&b)!=EOF){
if(a>b)swap(a,b);
int k=b-a;
int ans=(a!=floor(k*(1.0+sqrt(5.0))/2));
printf("%dn",ans);//0必败态 1必胜态
}
return 0;
}
尼姆博奕(Nimm Game)
有k堆各若干个物品,两个人轮流从某一堆取任意多的物品,规定每次至少取一个,多者不限,最后取光者得胜。
对于多堆石子 ( a 1 , a 2 , a 3 . . . a k ) (a_1,a_2,a_3...a_k) (a1,a2,a3...ak) , 如果所有都是0 , 那么是一个N态
当多堆石子异或后结果为0 , 则是一个N态 , 否则为P态4
int main(){
int m,ans,n;
while(~scanf("%d",&m)){
n=ans=0;
while(m--)
scanf("%d",&n),ans^=n,printf("ans=%dn",ans);
if(ans)printf("Yesn");
else printf("Non");
}
}
证明:
当你拿到一个异或为0的状态(没取完) , 取任意一个数 , 这个数因为不能是0 , 所以在二进制中一定有几位会是1 , 也就是说剩下的异或后不会是0即还有石子没取完
而可以证明对方可以取一个数使剩下的石子数异或为0 , 即:维护异或为0的状态
证明 : 假设异或后为(1010) , 那么一定会有一堆石子的大小大于>=(1000) , 我们对于这堆取出(1000) , 剩下的就变成了(0010) , 这个时候我们再塞回去(0010) ( 这个是重点 , 塞在自己的堆里面 , 和别的堆的0010异或后为0000 , 如果0010是自己堆的就更好处理了 , 直接取掉变成0就可以了 ) , 就可以了 |
斐波那契博弈(Fibonacci Game)
有一堆石子,两个人轮流从其中取走一定的石子,取走最后所有石子的人为赢家,不过得遵循如下规则:
1.第一次取不能取完,至少取1颗.
2.从第二次开始,每个人取的石子数至少为1,至多为对手刚取的石子数的两倍。
当n为Fibonacci数时,先手必败。否则先手必胜
证明:根据“Zeckendorf定理”(齐肯多夫定理):任何正整数可以表示为若干个不连续的Fibonacci数之和。如n=83 = 55+21+5+2,假如先手取2颗,那么后手无法取5颗或更多,而5是一个Fibonacci数,那么一定是先手取走这5颗石子中的最后一颗,同理,接下去先手取走接下来的后21颗中的最后一颗,再取走后55颗中的最后一颗,那么先手赢。
反之:如果n是Fibonacci数,如n=89:记先手一开始所取的石子数为y
(1)若y>=34颗(也就是89的向前两项),那么一定后手赢,因为89-34=55=34+21<2*34。
(2)y<34时剩下的石子数x介于55到89之间,它一定不是一个Fibonacci数,把x分解成Fibonacci数:x=55+f[i]+…+f[j],若,如果f[j]<=2y,那么对B就是面临x局面的先手,所以根据之前的分析,后手只要先取f[j]个即可,以后再按之前的分析就可保证必胜。
注脚 :
显然 , a是递增的 , 而k也是递增的 , 所以b是递增的 , 所以只需要排除a和b重复的情况 .
设 a [ i ] , b [ j ] a[i],b[j] a[i],b[j] , 如果 i < j i<j i<j , 那么 b [ j ] > a [ i ] b[j]>a[i] b[j]>a[i] ; 反之 , a是会选择前面没有出现过的数 , 自然不会选和b相同的数 ↩︎减一个数的话 , 因为所有数不重复 , 另一个数肯定不会和剪掉后的那个数匹配
两个减去相同数 , 因为k也是不会重复的 , 所以剪完后也不会是奇异局势 ↩︎对于每个数 , 一定可以找到一组奇异局势满足这个数在其中出现 , 那么如果匹配了a , 局势中的b比你手中的b小 ,你就可以得到局势中的b ; 如果不行就匹配b , 可证明a或b一定有一个可以完成匹配 ↩︎
- ↩︎
最后
以上就是怡然枫叶为你收集整理的组合博弈基础 -- 三大基本博弈+斐波那契博弈的全部内容,希望文章能够帮你解决组合博弈基础 -- 三大基本博弈+斐波那契博弈所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复