您的位置:首页 > 其它

uva 10561 - Treblecross(Nim)

2014-08-05 23:38 423 查看
题目链接:uva 10561 - Treblecross

题目大意:n个格子排成一排,其中一些格子有'X',两个游戏者轮流操作,在格子中放X,如果此时出现连续3个X,则获胜。给出先手是否可以取胜,取胜方案的第一步该怎么走。

解题思路:一个X可以导致左右两个的两个格子都不能再放X,因为如果出现XX.、.XX、X.X,那么下一个人肯定胜利。所以对于长度为n的格子序列,g(x)=maxg(x−3),g(x−4)...g(2)XORg(n−7).

所以可以预先处理出g数组,然后对于给定的序列,枚举先手下的位置,判断这种情况下,后手是否为必败态。注意如果先手一步即可胜利要特殊考虑。
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;
const int maxn = 200;

int g[maxn+5], v[maxn+5];

int SG (int s) {
memset(v, 0, sizeof(v));

for (int i = 1; i <= s; i++) {
int t = 0;
if (s - i - 2 >= 0)
t ^= g[s-i-2];
if (i - 3 >= 0)
t ^= g[i-3];
v[t] = 1;
}
int mv = -1;
while (v[++mv]);
return mv;
}

void init () {
memset(g, 0, sizeof(g));
g[1] = g[2] = g[3] = 1;
for (int i = 4; i <= 200; i++)
g[i] = SG(i);
}

int n, len, pos[maxn+5];
char str[maxn+5];

bool check () {
int pre = -3, ret = 0;

for (int i = 0; i <= len; i++) {
if (str[i] == 'X') {
if (i - pre <= 2)
return false;
int l = max(i - pre - 5, 0);

if (l)
ret ^= g[l];
pre = i;
}
}

int l = max(len - pre - 3, 0);
if (l)
ret ^= g[l];
return ret == 0;
}

bool judge () {
n = 0;
len = strlen(str);

for (int i = 0; i < len; i++) {
if (str[i] == '.') {
str[i] = 'X';
if (check())
pos[n++] = i + 1;
str[i] = '.';
}

if (i && i < len - 1 & str[i-1] == 'X' && str[i+1] == 'X')
pos[n++] = i + 1;

if (i < len - 2 && str[i+1] == 'X' && str[i+2] == 'X')
pos[n++] = i + 1;

if (i >= 2 && str[i-1] == 'X' && str[i-2] == 'X')
pos[n++] = i + 1;
}
return n;
}

int main () {
init();
int cas;
scanf("%d", &cas);
while (cas--) {
scanf("%s", str);
printf("%s\n", judge() ? "WINNING" : "LOSING");

if (n)
printf("%d", pos[0]);
for (int i = 1; i < n; i++)
printf(" %d", pos[i]);
printf("\n");
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: