佐威夫博弈:
适用题型:
有两堆各若干个物品,两个人轮流从任意一堆中取出至少一个或者同时从两堆中
取出同样多的物品,规定每次至少取一个,至多不限,最后取光者胜利。
我们把先手必输的局势定义为“奇异局势”;
第一种(0,0)第二种(1,2)
第三种(3,5)
第四种 (4 ,7)
第五种(6,10)
第六种 (8,13)
第七种 (9 , 15)
第八种 (11 ,18)
第n种 (a[k],b[k]) 每种奇异局势的第一个值(这里假设第一堆数目小于第二堆的数目)总是等于当前局势的差值乘上1.618
我们都知道0.618是黄金分割率。而威佐夫博弈正好是1.618,这就是博弈的奇妙之处
在编程题中,有些题目要求精度较高,我们可以用下述式子来表示这个值
1.618 = (sqrt(5.0) + 1) / 2
详解:点击这里
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
double p=(sqrt(5.0)+1)/2.0;//差值*1.618==minn(两堆中较小那堆的数量)
//若相等为奇异局势,先手必败
void solve()
{
double n,m,c;
while(~scanf("%lf %lf",&n,&m))
{
c=(n-m)>0?n-m:m-n;
n=n<m?n:m;
if(int(c*p)==int(n))
printf("0\n");
else
printf("1\n");
}
}
int main()
{
solve();
return 0;
}
巴什博弈:
适用题型: 只有一堆n个物品,两个人轮流从这堆物品中取物, 规定每次至少取一个,最多取m个。最后取光者得胜。(必须是一堆才试用哦。)
我们不难发现如果我们起手面对的情况是(n+1)k(k=0,1,2…n)的情况就必输了,n就是最多可以拿的石子个数。 此时就属于奇异局,必败。
相反的,如果你不是处于奇异局,比如是(n+1)k+r,拿出r个石子,你的对手就进入奇异局,己方必胜;
详解:点击这里
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n, m;
while (cin >> n >> m)//n:物品数目,m:最多取的个数
{
if (n % (m + 1) == 0)//必败,奇异局
cout << "Send to you!" << endl;
else //必胜
cout << "I'm first!" << endl;
}
return 0;
}
尼姆博弈:
适用题型: 有若干堆石子,每堆石子的数量是有限的,二个人依次从这些石子堆中拿取任意的石子,至少一个(不能不取),最后一个拿光石子的人胜利。
用0与每个数异或,如最后结果为0,则后手胜(设一数组a[m],令sum=0,循环与数组每一个数据异或(sum^=a[i]),sum最后等于0则后手胜)
如果我们面对的是一个非必败态(a,b,c),要如何变为必败态呢?(XOR表示异或)
假设 a < b < c,我们只要将 c 变为a XOR b,即可。因为有如下的运算结果:
a XOR b XOR (a XOR b)=(a XOR a) XOR (b XOR b) = 0 XOR 0 = 0
要将c 变为a XOR b,只要对 c进行 c-(a XOR b)这样的运算即可
详解:点击这里
HDU - 2176
Problem Description m堆石子,两人轮流取.只能在1堆中取.取完者胜.先取者负输出No.先取者胜输出Yes,然后输出怎样取子.例如5堆 5,7,8,9,10先取者胜,先取者第1次取时可以从有8个的那一堆取走7个剩下1个,也可以从有9个的中那一堆取走9个剩下0个,也可以从有10个的中那一堆取走7个剩下3个.
Input
输入有多组.每组第1行是m,m<=200000. 后面m个非零正整数.m=0退出.
Output
先取者负输出No.先取者胜输出Yes,然后输出先取者第1次取子的所有方法.如果从有a个石子的堆中取若干个后剩下b个后会胜就输出a b.参看Sample Output.
Sample Input
2
45 45
3
3 6 9
5
5 7 8 9 10
0
Sample Output
No
Yes
9 5
Yes
8 1
9 0
10 3
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
using namespace std;
int a[200001];
int main()
{
int i,j,n,m,k;
while(~scanf("%d",&n)&&n)
{
for(i=0;i<n;i++)
scanf("%d",&a[i]);
m=a[0];
for(i=1;i<n;i++)
{
m=m^a[i];
}
if(m==0)
printf("No\n");
else
{
printf("Yes\n");
for(i=0;i<n;i++)
{
k=m^a[i]; //将异或得到的答案跟其中a[i]再异或一次就相当于把a[i]去除后
//剩下的所有的异或得到的值,如果该值比a[i]小说明可以从a[i]
//中去除一部分得到该值,两个相等的值异或便得到0,即可
if(k<a[i])
printf("%d %d\n",a[i],k);
}
}
}
return 0;
}
斐波那契博弈:
题型: 有一堆个数为n(n>=2)的石子,游戏双方轮流取石子,规则如下:
1)先手不能在第一次把所有的石子取完,至少取1颗;
2)之后每次可以取的石子数至少为1,至多为对手刚取的石子数的2倍。
约定取走最后一个石子的人为赢家。
结论:当n为斐波那契数的时候,先手必败。
f[i]:1,2,3,5,8,13,21,34,55,89……
详解:点击这里