首页 > 代码库 > UVA - 10561 Treblecross (SG定理)
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(x?3),g(x?4),g(x?5),g(1) or g(x?6)... } ,就是枚举长度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; }