题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=1527
题目描述:
有两堆石子,数量任意,可以不同。游戏开始由两个人轮流取石子。游戏规定,每次有两种不同的取法,一是可以在任意的一堆中取走任意多的石子;二是可以在两堆中同时取走相同数量的石子。最后把石子全部取完者为胜者。现在给出初始的两堆石子的数目,如果轮到你先取,假设双方都采取最好的策略,问最后你是胜者还是败者。
首先介绍一下威佐夫博弈(Wythoff Game)的概念:
有两堆各若干个物品,两个人轮流从某一堆或同时从两堆中取同样多的物品,规定每次至少取一个,多者不限,最后取光者得胜。
性质:两个人如果都采用正确操作,那么面对非奇异局势,先拿者必胜;反之,则后拿者取胜。
判断是否为奇异局势:任给一个局势(a,b), (下面用到的a是两者中较小的数)ak =[k(1+√5)/2],bk= ak + k (k=0,1,2,…,n 方括号表示取整函数)
奇妙的是其中出现了黄金分割数(1+√5)/2 = 1。618…,因此,由ak,bk组成的矩形近似为黄金矩形,由于2/(1+√5)=(√5-1)/2,可以先求出j=[a(√5-1)/2],
若a=[j(1+√5)/2],那么a = aj,bj = aj + j,若不等于,那么a = aj+1,bj+1 = aj+1+ j + 1,
若都不是,那么就不是奇异局势。然后再按照上述法则进行,一定会遇到奇异局势。
我们再用具体的数值说明一下:
当面对(0,0)时很显然我们是处于必败的状态,而下一个该状态即(1,2)
因为无论我们做(0,2)(1,1)(1,0)那种操作对方都能使我们变成(0,0)
以此类推,前几个奇异局势是:(0,0)、(1,2)、(3,5)、(4,7)、(6,10)、(8,13)、(9,15)、(11,18)、(12,20)。
而他们的差值就是0,1,2,3,4,5,6,7……
所以第一个值 = 差值 * 1.618满足黄金分割数的比例。
这是为什么呢?
首先,若 (x, y) 是必败态,那么(x+i,y),((x,y+i)肯定是必胜态,因为我可以通过拿去i个石子使其变成(x,y)
这也就说明了,以后的必败态绝对不会再出现x、y。因为如果出现,我可以通过改变另一个值使它变为(x,y),那么就不是必败态了。
首先,假设我们得到状态 (a[i] - p, a[i] - p + y),并且比 a[i] 小的数都在之前出现过,若 a[i] - p 存在必败态 ,那么当前状态 (a[i] - p, a[i] - p + y)肯定是必胜态了
若 a[i] - p 出现在较大的数,由于小数是单增的,因而其对应的小数必小于 a[i] + y,故而也可推出其状态为必胜态。
于是,(a[i], a[i] +y) 状态的胜负性只与状态 (a[i], a[i] + d) (d <y) 有关。不难看出,y= i 时恰为必败态,因为不论从第二堆中取出多少个石子,作为另一堆的第一堆石子并没有在之
前出现过,所以得到的一定是一个必胜态,因而 (a[i], a[i] + y) 为必败态,即矩阵i 个必败态大数等于小数加上 i。
所以差值就是0,1,2,3,4,5,6,7……了
#include<stdio.h>#include<math.h>int main(){int a,b;while(~scanf("%d%d",&a,&b)){double j,k,r;int t;if(a>b){t=a;a=b;b=t;}r=(sqrt(5.0)-1)/2;j=(int)(r*a);if(a!=(int)(j/r))j+=1;if(b!=(int)(j/r)+j)printf("1\n");elseprintf("0\n");}return 0;}
题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=2177
原理相同
#include<stdio.h>#include<math.h>int main(){ int a,b; while(~scanf("%d%d",&a,&b)&&(a||b)) { double j,k,r,x; int i,n,m,m_n; int t; if(a>b) { t=a; a=b; b=t; } r=(sqrt(5.0)-1)/2; x=r+1; j=(int)(r*a); if(a!=(int)(j/r)) j+=1; if(b==(int)(j/r)+j) printf("0\n"); else { printf("1\n"); for(i=1;i<=a;i++){n=a-i;m=b-i;m_n=m-n;if((int)(m_n*x)==n)printf("%d %d\n",n,m);}for(i=b-1;i>=0;i--){n=a;m=i;if(n>m){t=n;n=m;m=t;}m_n=m-n;if((int)(m_n*x)==n)printf("%d %d\n",n,m);}} } return 0;}
共同学习,写下你的评论
评论加载中...
作者其他优质文章