1.组合游戏的定义:
组合游戏是一个常见的概念,它是是满足这样一些条件的游戏:
1) 游戏有2名参与者,每个人都采用对自己最有利的策略。
2) 参与者操作时可以的操作时将游戏从当前状态改变为另一状态。
3) 参与者轮流进行操作,每个玩家可选择的状态是固定的,没有随机成分
4) 在游戏出于某状态,当前参与者不能进行操作时,游戏结束。此时参照规则决定胜负。
5) 无论参与者做出怎样的操作游戏在有限部数之内结束(没有平局),所以组合游戏必然是一个无环图。
组合游戏也可以用一个有向图来表示 G=(X,F)X为游戏的状态集合F(X)为X可以到达的状态集合,而结束状态均宣布当前参与者失败。
这类博弈问题还有若干分类。
规定移动最后一步的游戏者胜的规则叫做Normal Play Rule。
规定移动最后一步的游戏者输的规则叫做Misere Play Rule 也称Anti-SG games。
此外,对于游戏的双方,如果二者博弈的规则相同,那么称这类游戏是impartial games否则称为partizan games 。
实际上,解决partizan games的方法和普通的SG games是有区别的,一般会采用动态规划或者surreal number。
2.必胜局面
组合游戏的必胜状局面定义为当前玩家有策略能使无论对手做什么操作也可以保证自己胜利的状态。
1) 结束状态的性质由规则决定。
2) 一个非结束状态,如果它能到达任何必败状态,那么它是必胜状态,否则它就是必败状态。
3.Sprague-Grundy 函数
它是定义在组合游戏状态上的函数,用g (X)表示X状态的函数值。
定义为:
g (X)= min{n| n∈N ,n≠ for y∈F(x)}
形象的说就是X的函数值为与X所能到达的任意点函数值不同的最小自然数。
我想细心的读者已经发现g (X)=0当且仅当X为必败状态,这用其定义很容易验证:
1) 当X为结束状态时,由于g (X)=0它是必败状态。
2) 当X不是结束状态时,如果它能到达必败状态,那么g (X)>0,X是必胜状态。
3) 如果X不是结束状态且它到达的所有状态未必败状态,那么g (X)=0它是必败状态。
(一)巴什博奕(Bash Game):
只有一堆n个物品,两个人轮流从这堆物品中取物,规定每次至少取一个,最多取m个.最后取光者得胜.
n = (m+1)r+s , (r为任意自然数,s≤m), 即n%(m+1) != 0, 则先取者肯定获胜。
巴什博弈还是很好理解的,以你是先手的角度考虑,每一局你都必须构建一个局势,每次都留给对手m+1的倍数个物品。所以不只是取物品中的博弈可以用到巴什定理,还可以是报数之类的,看谁先报到100.并且每次报的数必须是1~10(包括1跟10),那么你每次都应该留给对手剩下的报数个数为11的倍数。如果n=m+1,那么由于一次最多只能取m个,所以,无论先取者拿走多少个,后取者都能够一次拿走剩余的物品,后者取胜。因此我们发现了如何取胜的法则:如果n=(m+1)r+s,(r为任意自然数,s≤m),那么先取者要拿走s个物品,如果后取者拿走k(≤m)个,那么先取者再拿走m+1-k个,结果剩下(m+1)(r-1)个,以后保持这样的取法,那么先取者肯定获胜。总之,要保持给对手留下(m+1)的倍数,就能最后获胜。
题目:
HDU1846:常规做法
#include
int main()
{
int m,n,i,c;
while(~scanf("%d",&c))
{
while(c--)
{
scanf("%d%d",&m,&n);
bool flag=true;
if(m%(n+1)==0)
flag=false;
if(flag)
printf("first\n");
else
printf("second\n");
}
}
return 0;
}
#include
int main()
{
int n;
while(~scanf("%d",&n))
{
if(n%3==0)
printf("Cici\n");
else
printf("Kiki\n");
}
return 0;
}
#include
using namespace std;
int main()
{
int n,m;
while(cin>>n>>m,m+n)
{
puts((n%2&&m%2)?"What a pity!":"Wonderful!");
}
return 0;
}
#include
int main()
{
int n,m;
while(~scanf("%d%d",&m,&n))
{
if(m%(n+1)==0)
printf("none\n");
else if(n>m)
{
printf("%d",m);
for(int i=m+1;i<=n;i++)
{
printf("% d",i);
}
printf("\n");
}
else
printf("%d\n",m%(n+1));
}
return 0;
}
#include
int main()
{
int c,n,m;
while(~scanf("%d",&c))
{
while(c--)
{
scanf("%d%d",&n,&m);
if(n%(m+1)==0)
printf("Rabbit\n");
else
printf("Grass\n");
}
}
}
#include
int main()
{
int n,p,q;
while(~scanf("%d%d%d",&n,&p,&q))
{
if(n%(q+p)>0&&n%(q+p)<=p)
printf("LOST\n");
else
printf("WIN\n");
}
return 0;
}
理解了bash的规则这种题还是很水的
(二)威佐夫博奕(Wythoff Game)
有两堆各若干个物品,两个人轮流从某一堆或同时从两堆中取同样多的物品,规定每次至少取一个,多者不限,最后取光者得胜。用(a[k],b[k])(a[k] ≤ b[k] ,k=0,1,2,...,n)表示两堆物品的数量并称其为局势,如果甲面对(0,0)甲输,称这种局势为奇异局势。前几个奇异局势是:(0,0),(1,2),(3,5),(4,7),(6,10),(8,13),(9,15),(11,18),(12,20)。
仔细观察规律可以发现可以看出:
#include
#include
int main()
{
int n,m,temp,k;
while(~scanf("%d%d",&n,&m))
{
if(n
#include
#include
#include
#define MAX 99999999
int main()
{
int n,m,t,i;
double q;
q=(sqrt(5.0)+1)/2.0;
while(~scanf("%d%d",&n,&m)&&(n||m))
{
t=(int)(q*(m-n));
if(n!=t)
{
printf("1\n");
printf("%d %d\n",t,m-(n-t));
int x;
for(i=0;i<=m;i++)
{
x=m-i;
if(x>n)
{
if( (int)(q*(x-n))==n )
printf("%d %d\n",n,x);
}
else if(x
(三)尼姆博奕(Nimm Game):