入门题:POJ1067
威佐夫详解
例如,两堆石子,两种取法,要么在一堆中取任意数量,要么在两堆中取同等数量,取完者胜。
根据前人研究,先手的必败局为(m,n)【其中 min(m,n) == | m - n | *1.618】
在当前局势必胜的情况下,可以通过枚举差值使其满足必败局的条件,得到下一步的取法。
#include <iostream>
#include<cstdio>
#include<math.h>
using namespace std;
const double g = (sqrt(5.0) + 1) / 2; //1.618 这种算法比较准确
bool validate(int a,int b){
if(a > b)swap(a,b);
int k = b - a;
if(a == (int)(g * k)) return true; //注意int是下取整
else return false;
}
int main(){
int n,m;
while(scanf("%d%d",&n,&m) != EOF){
if(validate(n,m))printf("0\n");
else {
printf("1\n");
//在两堆石子中同时取,从1枚举到最小数
int a = min(n,m);
int b = max(n,m);
int ans = 0;
//取完之后让对手面对必败局
for(int i = 1; i <= a;++i){
if(validate(a-i,b-i)) printf("%d %d\n",a-i,b-i);
}
//仅从一堆中取
for(int i = b - 1;i >= 0;--i){
if(validate(a,i))printf("%d %d\n",a,i);
}
}
}
return 0;
}
}