UVA - 10561 Treblecross (SG定理)

Treblecross is a two player gamewhere the goal is to get three X in a row on a one-dimensional board. At the startof the game all cells in the board is empty. In each turn a player puts a X in an empty cell, and if that results in there beingthree X next to each other, that player wins.

Given the current state of the game, you are todetermine if the player to move can win the game assuming both players playperfectly. If so, you should also print all moves that will eventually lead toa win.

Consider the game where the board size is 5cells. If the first player puts a X at position three (in the middle) so thestate becomes ..X.., he will win the game as no matter where the other playerputs his X, the first player can get three X in a row. If, on the other hand,the first player puts the X in any other position, the second player will winthe game by putting the X in the opposite corner (for instance, after thesecond player moves the state might be .X..X). This will force the first playerto put an X in a position so the second player wins in the next move.

Input

The input begins with an integer N (N<100),the number of states that will follow. Each state is represented by a string ona line by itself. The string will only contain the characters '.' and 'X'. Thelength of the string (the size of the board) will be between 3 and 200characters, inclusive. No state will contain three X in a row.

 

Output

For each case, first output WINNING or LOSING depending onif the player to move will win or lose the game. On the next line, output inincreasing order all positions on the board where the player to move may put anX and win the game. The positions should be separated by a blank, and be inincreasing order. The leftmost position on the board is 1.

 

SampleInput                                             Outputfor Sample Input

4

.....

X.....X..X.............X....X..X

.X.X...X

...............................................

 

WINNING

3

LOSING

 

WINNING

3

WINNING

1 12 15 17 20 24 28 31 33 36 47

 


Problemsetter:Jimmy Mårdell, Member of Elite Problemsetters' Panel

题意:有n个格子排成一行,其中一些格子里面有字符X,两个游戏者轮流操作,每次都可以选个空格,在里面放上字符X,如果此时有3个连续的X出现,则该游戏者赢得比赛

起始情况下不会有3个连续的X出现,你的任务是判断先手是必胜或者必败,必胜输出所有的策略

思路:如果输入中已经有3个连续的了,如果有可能实现三个连续的话,那么就是必胜的啦,这是可以直接判断的。还有一个比较明显的结论是:我们不会在X的附近两个放X的

,我们把这块称为“禁区”,那么整个格子就被我们分成若干个部分,设g(x)表示长度为x的所对应的SG函数值,那么我们就可以得到递推式:

g(x)=mex   { g(x3),g(x4),g(x5),g(1) or g(x6)...                } ,就是枚举长度x时候从后往前放X后的可能情况

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
const int maxn = 210;

int SG[maxn];
char str[maxn], tmp[maxn];

int cal(int x) {
	if (x < 0)
		return 0;
	if (SG[x] != -1)
		return SG[x];

	int vis[maxn];
	memset(vis, 0, sizeof(vis));
	for (int i = 1; i <= x; i++) 
		vis[cal(i-3)^cal(x-i-2)] = 1;
	for (int i = 0; ; i++)
		if (!vis[i])
			return SG[x] = i;
}

int judge(int x) {
	if (str[x] == 'X')
		return 0;
	strcpy(tmp, str);
	tmp[x] = 'X';
	int len = strlen(str);

	for (int i = 0; i+2 < len; i++)
		if (tmp[i] == 'X' && tmp[i+1] == 'X' && tmp[i+2] == 'X')
			return 1;
	for (int i = 0; i < len; i++) {
		if (i+1 < len && tmp[i] == 'X' && tmp[i+1] == 'X')	
			return 0;
		if (i+2 < len && tmp[i] == 'X' && tmp[i+2] == 'X')
			return 0;
	}

	int ans = 0,flag = 0, w = 2, cnt = -1;
	for (int i = len-1; i >= 0; i--) 
		if (tmp[i] == 'X') {
			cnt = i;
			break;
		}
	for (int j, i = 0; i < len; i++) {
		if (i > cnt)
			w = 0;
		if (tmp[i] == 'X')
			flag = 2;
		if (tmp[i] != '.')
			continue;
		for (j = i; j < len && tmp[j] == '.'; j++) ;
		ans ^= cal(j-i-flag-w);
		i = j-1;
	}

	return ans == 0;
}

int main() {
	memset(SG, -1, sizeof(SG));
	int t;
	scanf("%d", &t);
	while (t--) {
		scanf("%s", str);
		vector<int> ve;
		for (int i = 0; i < strlen(str); i++) 
			if (judge(i))
				ve.push_back(i);

		if (ve.size()) {
			printf("WINNING\n");
			for (int i = 0; i < ve.size()-1; i++)
				printf("%d ", ve[i]+1);
			printf("%d\n", ve[ve.size()-1]+1);
		}
		else printf("LOSING\n\n");
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值