HDU - 3595 GG and MM ( Every - SG)

题意: 就是有n个游戏,一个游戏中有两堆石子,每次你可以再多的一堆中拿走k倍的少的石子,多个游戏同时进行,每个游戏必须都玩完问你最后谁输谁赢。

思路:同样来自贾志豪2009年的集训队论文,这里也直接说结论好了:

我们感性的认知一下,这种每个游戏都要玩,同时经行的游戏,我们如何赢?贪心的想一下就是对于我们可以赢得游戏,我们要玩的尽量慢一点,拿对于我们必输的游戏我们要让他尽量结束,所以对于这中游戏我们要维护一个stept的步数,

对于我们能赢的游戏我们要取最大值,对于我们输的游戏我们要去最小值,那么先手必胜的条件就是这个游戏中的最大步数是奇数,对于证明 。。。不会 大家可以看一下贾志豪的论文,可能在不远的将来我会写一遍观后感,主要是 ,,,内容太多,啃不动啊 啊啊啊啊啊 。

代码:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1000+10;
int sg[maxn][maxn];
int stept[maxn][maxn];
int getsg(int x,int y)
{
	if(sg[x][y] != -1) return sg[x][y];
	if(x > y) swap(x,y);
	if(x == 0){ // 如果x等于0说明游戏结束 ,这时stept 和 sg值都是0 
		sg[x][y] = sg[y][x] = 0;
		stept[x][y] = stept[y][x] = 0;
		return sg[x][y];
	}
	int MIN = 9999999,MAX = -1;  
	for(int i = x ; i <= y ; i += x)//当前游戏的子游戏 
	{
		if(getsg(x,y-i) == 0)// 这里 和敌对搜索一样,如果我们当前有一个必败态那么当前肯定是一个必胜态 
		{
			MAX = max(MAX,stept[x][y-i]+1); //之后求最大值 ,不要忘记stept[x][y-i]要+1 
			sg[x][y] = sg[y][x] = 1;//必胜态 
		}
		else {
			MIN = min(MIN,stept[x][y-i] + 1);  
		}
	}
	if(sg[x][y] == 1) stept[x][y] = stept[y][x] = MAX; // 如果是必胜那么就是最大值 
	else
	{
		stept[x][y] = stept[y][x] = MIN; //反之 
		sg[x][y] = sg[y][x] = 0; //都是必胜态 说明当前是一个必败态 
	}
	return sg[x][y];
 
}
int main()
{
	int n;
	memset(sg,-1,sizeof(sg));
	while(scanf("%d",&n)!=EOF)
	{
		
		int maxn = -1,x,y;
		for(int i =0  ;i  < n ;i ++)
		{
			scanf("%d%d",&x,&y); //对于每一个游戏,得到他的sg值和他的 stept ,之后维护一个最大值 
			getsg(x,y);
			maxn = max(stept[x][y],maxn);
		}
		if(maxn&1) puts("MM");
		else puts("GG");
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/wjmwsgj/article/details/80203631
gg