Problem C Treblecross Input: Standard Input

Output: Standard Output

Time Limit: 4 Seconds

Treblecross is a two player game where the goal is to get three X in a row on a one-dimensional board. At the start of 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 being three X next to each other, that player wins.

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

Consider the game where the board size is 5 cells. If the first player puts a X at position three (in the middle) so the state becomes ..X.., he will win the game as no matter where the other player puts 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 win the game by putting the X in the opposite corner (for instance, after the second player moves the state might be .X..X). This will force the first player to 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 on a line by itself. The string will only contain the characters '.' and 'X'. The length of the string (the size of the board) will be between 3 and 200 characters, inclusive. No state will contain three X in a row.

Output

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

Sample Input                                             Output for 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

 


题目大意:有n个格子排成一行,其中一些格子里面有字符X。两个选手轮流操作,每次选一个空格,在里面放字符X。如果此时有3个连续的X出现,则该玩家获得胜利。

你的任务是判断先手必胜还是必败,若必胜则,输出所有毕生策略(第一步)。

分析:

遍历每个能操作的位置

(1)若先手走一步后已出现3个连续的X,则此操作为必胜策略。

(2)不能一步定胜负的情况。先手选择一步后,遍历后手的操作。

       1:若后手一步能达到3个连续的X,则先手的操作不是必胜策略。

       2:第一个操作跟第二个操作都不能判定胜负,求sg函数。

一段全是空白的格子,把X放在任意一个位置,它的右边两个格子跟左边的两个格子(存在的格子)谁去放谁输。每位选手都是用最优的策略,所以X附近的这几个为禁区,拆分为子游戏的时候属于禁区的格子直接不要。

整个游戏,可以看成若干子游戏。g(x)=mex{g(x-3),g(x-4),g(x-5),g(1) xor g(x-6),g(2) xor g(x-7).....}

AC代码:

#include<iostream>
#include<string>
#include<cstdio>
#include<vector>
#include<cstring>
using namespace std; vector<int> v;
int sg[]; int Max(int a,int b)
{
return a>b?a:b;
} int mex(int n)
{
bool flag[];
int i,t;
if(sg[n]!=-) return sg[n];
if(n==) return sg[n]=;
memset(flag,false,sizeof(flag));
//i位置放X,它左边两个跟右边两个都为禁区,谁再放X谁输
for(i=;i<=n;i++)
{
//一个游戏分成两个子游戏
t=(mex(Max(,i-))^mex(Max(,n-i-)));
flag[t]=true;
}
for(i=;i<;i++)
if(!flag[i]) break;
return sg[n]=i;
}
bool is_oi(string s) //判断先手是否已经胜利
{
for(int i=;i<s.size()-;i++)
if(s[i]=='X' && s[i+]=='X' && s[i+]=='X')
return true;
return false;
} bool is_oi1(string s) //先手一步后,不能确认先手胜利的情况
{
int i;
for(i=;i<s.size();i++)//后手一步后,若后手必胜了,就没判断的必要了
{
if(s[i]=='.')
{
s[i]='X';
if(is_oi(s)) return false;
s[i]='.';
}
}
int ans=;//整个游戏的SG值
int num=;//子游戏的格子个数
for(i=;i<s.size();i++)//找子游戏(子游戏的定义:一段空白格子两端端点以外的X不影响游戏的结果)
{
//X的前两个空格跟后两个空格都不是最优的走法(必败),所以子游戏(两个X之间一段空白的格子减去每个X附近的两个格子数)
if(s[i]=='X'||(i>=&&s[i-]=='X')||(i>=&&s[i-]=='X')||(i+<s.size()&&s[i+]=='X')||(i+<s.size()&&s[i+]=='X'))
{ans^=mex(num);num=;}
else num++;
}
ans^=mex(num);
if(ans==)
return true;
return false;
} void solve(string s)
{
for(int i=;i<s.size();i++)//先手走一步后,看后手的状态
{
if(s[i]=='.')
{
s[i]='X';
if(is_oi(s) || is_oi1(s)) //如果先手这一步,后手的状态是必败的,记录位置
v.push_back(i+);
s[i]='.';
}
}
} int main()
{
memset(sg,-,sizeof(sg));
int t;
string s;
cin>>t;
while(t--)
{
v.clear();
cin>>s;
solve(s);
if(v.size()==) //先手没有必胜的情况,肯定必败。
cout<<"LOSING"<<endl<<endl;
else
{
cout<<"WINNING"<<endl;
for(int i=;i<v.size();i++)
printf(i?" %d":"%d",v[i]);
cout<<endl;
}
}
return ;
}

uva 10561 sg定理的更多相关文章

  1. UVa 10561 (SG函数 递推) Treblecross

    如果已经有三个相邻的X,则先手已经输了. 如果有两个相邻的X或者两个X相隔一个.,那么先手一定胜. 除去上面两种情况,每个X周围两个格子不能再放X了,因为放完之后,对手下一轮再放一个就输了. 最后当“ ...

  2. UVA 10561 - Treblecross(博弈SG函数)

    UVA 10561 - Treblecross 题目链接 题意:给定一个串,上面有'X'和'.',能够在'.'的位置放X.谁先放出3个'X'就赢了,求先手必胜的策略 思路:SG函数,每一个串要是上面有 ...

  3. HDU5795A Simple Nim SG定理

    A Simple Nim Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Tota ...

  4. HDU5724 Chess(SG定理)

    题目 Source http://acm.hdu.edu.cn/showproblem.php?pid=5724 Description Alice and Bob are playing a spe ...

  5. HDU 1851 (巴什博奕 SG定理) A Simple Game

    这是由n个巴什博奕的游戏合成的组合游戏. 对于一个有m个石子,每次至多取l个的巴什博奕,这个状态的SG函数值为m % (l + 1). 然后根据SG定理,合成游戏的SG函数就是各个子游戏SG函数值的异 ...

  6. SG函数和SG定理【详解】

    在介绍SG函数和SG定理之前我们先介绍介绍必胜点与必败点吧. 必胜点和必败点的概念:        P点:必败点,换而言之,就是谁处于此位置,则在双方操作正确的情况下必败.        N点:必胜点 ...

  7. 简单易懂的博弈论讲解(巴什博弈、尼姆博弈、威佐夫博弈、斐波那契博弈、SG定理)

    博弈论入门: 巴什博弈: 两个顶尖聪明的人在玩游戏,有一堆$n$个石子,每次每个人能取$[1,m]$个石子,不能拿的人输,请问先手与后手谁必败? 我们分类讨论一下这个问题: 当$n\le m$时,这时 ...

  8. 【bzoj3576】[Hnoi2014]江南乐 博弈论+SG定理+数学

    题目描述 两人进行 $T$ 轮游戏,给定参数 $F$ ,每轮给出 $N$ 堆石子,先手和后手轮流选择石子数大于等于 $F$ 的一堆,将其分成任意(大于1)堆,使得这些堆中石子数最多的和最少的相差不超过 ...

  9. SG函数&&SG定理

    必胜点和必败点的概念:        P点:必败点,换而言之,就是谁处于此位置,则在双方操作正确的情况下必败.        N点:必胜点,处于此情况下,双方操作均正确的情况下必胜. 必胜点和必败点的 ...

随机推荐

  1. 第1节 flume:15、flume案例二,通过自定义拦截器实现数据的脱敏

    1.7.flume案例二 案例需求: 在数据采集之后,通过flume的拦截器,实现不需要的数据过滤掉,并将指定的第一个字段进行加密,加密之后再往hdfs上面保存 原始数据与处理之后的数据对比 图一  ...

  2. Ckeditor for Drupal

      Ckeditor for Drupal   关于Drupal的所见即所得编辑器,Ckeditor是一个不错的选择,而且可以在Ckeditor官网直接下载到专为Drupal制作的版本: http:/ ...

  3. 【求助】NdisSend,自定义数据包发送失败?

    做ndis hook的时候,自定义了一个数据包,包结构应该没有问题,填充NDIS_PACKET结构是这样的,先初始化:        NdisAllocatePacketPool(&nStat ...

  4. ios 登录功能学习研究

    登录功能是我在湖畔做的第一个需求. 当时PD给我的草图和下图类似: (图片来自知乎iOS客户端登录界面) 不过需求中要求用户名或者密码错误时,输入框要抖动(类似Mac登录密码错误的抖动效果). 如果实 ...

  5. Fortran学习笔记2(变量声明)

    常数的申明方式 变量初始化 等价申明EQUIALENCE 类型转化 自定义类型 KIND用法 常数的申明方式 程序中所有处理的数据,有些事固定不变的常数,如圆周率π和重力加速度G等. 此时,程序员可以 ...

  6. python中enumerate()函数的用法

    描述: enumerate() 函数用于将一个可遍历的数据对象(如列表.元组或字符串)组合为一个索引序列,同时列出数据和数据下标,一般用在 for 循环当中.其英文意为:枚举,列举. 函数说明: 语法 ...

  7. GIMP语言设置

    初学GIMP,需要设置语言:点击 编辑 - 首选项 其他的配置如: 配置快捷键 自己熟悉吧!

  8. 如何创作用纯 CSS 绘制一支栩栩如生的铅笔

    效果预览 在线演示 按下右侧的"点击预览"按钮可以在当前页面预览,点击链接可以全屏预览. https://codepen.io/comehope/pen/PaZYBw 可交互视频教 ...

  9. React碰到v-if

    最近在重构公司老项目,由于本人以前的技术栈是vue, 换工作后发现现在公司的技术栈是react, 所以重构的过程是及其痛苦.加之项目又是几年前的老项目,不敢大改,比葫芦画瓢比比皆是.本文就介绍下遇到的 ...

  10. LeetCode(104) Maximum Depth of Binary Tree

    题目 Given a binary tree, find its maximum depth. The maximum depth is the number of nodes along the l ...