HDOJ 1525 Euclid's Game 博弈

题目大意是给定两个数a,b,Stan always starts.规则是,每次只能把比较大的数减去比较小的数的整数倍,最后两个数中只要有一个数为0就结束,最后操作了的人为胜

首先:对于a,b中的比较大的数max和比较小的数min,不管两个人怎么取,一定会到达min,max % min的状态

因为max在没有减到比min小的时候,后续的操作依然是对max减去min的倍数,而一旦max比min小了,因为max = k*min + b,只有k=0的时候max才会比min小

依次类推直到其中一个数为0

那么他们必定在到达min,max%min的状态的时候总共减去了max / min个min;(这个时候很容易就可以想到利用gcd了)

利用gcd求出每次到达下一个状态需要减去的min的数量,存在stack中,那么问题就变成了对于排成一列的很多堆石子,要在第一堆石子中取出任意数量的石子,取完第一堆之后才能取第二堆(相当于在max,min没有到达min,max%min状态前不能对min,max%min进行操作),依次取完,最后取完所有石子的人获胜

因为是顺序取石子,可以利用dp

我的代码:

#include<stdio.h>
#include<string.h>

int stack[101], snum;
bool dp[101];

int Max(int a, int b)
{
	return a > b ? a : b;
}

int gcd(int max, int min)
{
	stack[++ snum] = max / min;
	if(max % min == 0)
	{
		return min;
	}
	return gcd(min, max % min);
}

int main()
{
	int a, b, max, min, i;
	while(scanf("%d%d", &a, &b) != EOF && !(a == 0 && b == 0))
	{
		max = Max(a, b);
		min = a + b - max;
		if(max % min == 0)
		{
			printf("Stan wins\n");
			continue;
		}
		snum = 0;
		gcd(max, min);

		dp[snum + 1] = 0;
		for(i = snum; i >= 1; i --)
		{
			if(dp[i + 1] == 0 || dp[i + 1] == 1 && stack[i] > 1)
			{
				dp[i] = 1;
			}
			else
				dp[i] = 0;
		}
		if(dp[1])
		{
			printf("Stan wins\n");
		}
		else
			printf("Ollie wins\n");
	}
	return 0;
}

点赞