Gym - 101908B Marbles(sg函数)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Cymbals/article/details/83212213

题目:https://vjudge.net/contest/263079#problem/B

题目大意:两人玩游戏,棋盘上散布一些石头,谁先将其中任意一块移动到坐标(0,0)即赢,石头可以向左下角、左、下三个方向任意距离移动,求先手玩家的胜负。

这个游戏很显然可以用有向图表示,思考用sg函数求解。

但是有一些特殊情况并不能被sg表示。那就是x坐标轴、y坐标轴和x = y的轴上,这三条轴刚好符合了游戏规则,直接一发挪到(0,0)即胜。

对这种情况分先手后手探讨一下,如果一开始就出现这种石头,那先手者直接胜利。

如果先手没有这种情况,那么把石头走到这三种位置显然是愚蠢的行为…肯定不是最优策略,绝对不会走的。

因此这三种情况干脆在求sg的时候当不存在,然后特判一下就好了。

然后这题的必败态(sg = 0)则是点(1,2)和(2,1),如果走到这里,那显然就输了。

ac代码:

#include<bits/stdc++.h>
using namespace std;

int sg[105][105];
bool vis[205];

void grundy() {
	for(int i = 1; i <= 100; i++) {
		for(int j = 1; j <= 100; j++) {
			if(i == j) {
				continue;
			}
			memset(vis, 0, sizeof(vis));
			for(int k = 1, len = max(i, j); k <= len; k++) {
				int nextX = i - k;
				int nextY = j - k;
				if(nextX > 0 && nextX != j) {
					vis[sg[nextX][j]] = 1;
				}
				if(nextY > 0 && nextY != i) {
					vis[sg[i][nextY]] = 1;
				}
				if(nextX > 0 && nextY > 0 && nextX != nextY) {
					vis[sg[nextX][nextY]] = 1;
				}
			}
			int g = 0;
			while(vis[g]) {
				++g;
			}
			sg[i][j] = g;
		}
	}
}

int main() {
	grundy();
	int n, x, y, sum = 0;
	scanf("%d", &n);
	for(int i = 0; i < n; i++) {
		scanf("%d%d", &x, &y);
		if(x == y || x == 0 || y == 0){
			printf("Y\n");
			return 0;
		}
		sum ^= sg[x][y];
	}
	printf("%s\n", sum ? "Y" : "N");
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Cymbals/article/details/83212213