P1290 欧几里德的游戏(博弈,SG)

P1290 欧几里德的游戏

  • 题目描述
    欧几里德的两个后代Stan和Ollie正在玩一种数字游戏,这个游戏是他们的祖先欧几里德发明的。给定两个正整数M和N,从Stan开始,从其中较大的一个数,减去较小的数的正整数倍,当然,得到的数不能小于0。然后是Ollie,对刚才得到的数,和M,N中较小的那个数,再进行同样的操作……直到一个人得到了0,他就取得了胜利。下面是他们用(25,7)两个数游戏的过程:

Start:25 7

Stan:11 7

Ollie:4 7

Stan:4 3

Ollie:1 3

Stan:1 0

Stan赢得了游戏的胜利。

现在,假设他们完美地操作,谁会取得胜利呢?

  • 输入格式:
    第一行为测试数据的组数C。下面有C行,每行为一组数据,包含两个正整数M, N(M, N不超过长整型).
  • 输出格式:
    对每组输入数据输出一行,如果Stan胜利,则输出“Stan wins”;否则输出“Ollie wins”

思路:感觉这题很像尼姆博弈的变形,同样都是n堆石子任意拿,但是尼姆博奕是在任意一堆拿石子,而这个必须一堆一堆地拿,拿完这一堆才能拿下一堆.
然后我们这样想,假设当前堆谁拿了最后一个谁就必输,那么肯定希望把最后一个留给对方.所以假如我是先手,假如当前堆只有1个,那么我只能乖乖地拿了,必输.假如有两个,我肯定只拿一个,假如有三个我肯定拿两个, 这一点又很像巴什博奕,所有只要大于一个我就能赢.同理假如当前堆谁拿了最后一个谁就必赢,我是先手的话我肯定一次就拿完,所以无论有多少堆,只要当前堆大于一个先手必胜.
那么怎么知道当前堆拿最后一个是赢还是输,递归求解即可,假如n/m == 1,那么SG(n,m) = !SG(m,n%m),而SG(m,n%m)又能继续按照此规则判断,假如n/m> 1,则直接为必胜态.

代码:

#include
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
const ll mod = 1e9+7;
const int maxn = 2e5+5;
const double eps = 1e-12;
const int inf = 0x3f3f3f3f;
map::iterator it;

ll a,b;

int get_sg(ll x,ll y)
{
	if(y == 0) return 0;
	if(x/y> 1) return 1;
	return !get_sg(y,x%y);
}

int main()
{
	int t;
	cin>>t;
	
	while(t--)
	{
		scanf("%lld %lld",&a,&b);	
		if(a< b) swap(a,b);
		
		int f;
		if(a/b> 1) f = 1;
		else f = !get_sg(b,a%b);
		
		if(f)
			printf("Stan wins\n");
		else
			printf("Ollie wins\n");
	}
	
	return 0;
}

你可能感兴趣的:(博弈)