博弈论之威佐夫博弈篇(poj1067)
(简单看了一下poj上的通过率和内容之后选了这道题做,毕竟是为了练习Java?就不要选太复杂的了,手动狗头。)
博弈论
鉴于水平有限,就不给大家放一些概念性的东西了,可以自己百度。我理解的博弈论就是两个人之间进行公平对决都采用最优策略轮流对抗,直到分出胜负。
威佐夫博弈
有两堆各若干个物品,两个人轮流从任一堆取至少一个或同时从两堆中取同样多的物品,规定每次至少取一个,多者不限,最后取光者得胜。
poj1067这道题要求解的是先手的胜负。
这题拿到手之后感觉有点懵,然后凭着之前的一丢丢经验,开始思考,先手胜分两种情况:一种是两堆物品数量相同时,即(n,n),另一种是一堆被取光,另一堆还有物品。然后从小规模问题开始分析:1,0时必胜,1,1时必胜,1,2时必败。但是还是没有思路,然后去看了别人的题解,发现可以套公式,然后就很简单了。
请忽略上一段话,以下才是正文部分。
首先来介绍一下奇异局势
我们用(a[k],b[k])(a[k] ≤ b[k] ,k=0,1,2,…,n)表示两堆物品的数量并称其为局势,如果甲面对(0,0),那么甲已经输了,这种局势我们称为奇异局势。
两个人如果都采用正确操作,那么面对非奇异局势,先拿者必胜;反之,则后拿者取胜。简单来说奇异局势在这道题中就是甲的必败态。
奇异局势的性质:
1.任何自然数都包含在一个且仅有一个奇异局势中。
由于a[k]是未在前面出现过的最小自然数,所以有a[k] > a[k-1] ,而 b[k]= a[k] + k > a[k-1] + k > a[k-1] + k - 1 = b[k-1] > a[k-1] 。所以性质1成立。
2.任意操作都可将奇异局势变为非奇异局势。
3.采用适当的方法,可以将非奇异局势变为奇异局势。
奇异局势公式:
a[k]=m*(1+√5)/2 b[k]=a[k]+m;
然后可以可以套用公式,对于局势(x,y),x<y,如果(y-x)*(√5+1)/2=x,,那么这个局势(x,y)就是一个奇异局势,先手必败。反之先手有必胜策略。
C++代码
#include<iostream>
#include<math.h>
using namespace std;
int main(void)
{
int m,n,temp;
while((cin>>m>>n)!=0)
{
if(m>n)
swap(m,n);
if(floor((n-m)*((1+sqrt(5))/2))==m)
cout<<0;
else cout<<1;
}
return 0;
}
java代码
import java.util.*;
import java.lang.*;
class Main
{
public static void main(String args[])
{
Scanner sc = new Scanner(System.in);
while(sc.hasNext())
{
int m=sc.nextInt();
int n=sc.nextInt();
int temp;
if(m>n)
{
temp=m;
m=n;
n=temp;
}
if(Math.floor((n-m)*(Math.sqrt(5.0)+1)/2)==m)
System.out.println(0);
else
System.out.println(1);
}
}
}