uva 10561 sg定理
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定理的更多相关文章
- UVa 10561 (SG函数 递推) Treblecross
如果已经有三个相邻的X,则先手已经输了. 如果有两个相邻的X或者两个X相隔一个.,那么先手一定胜. 除去上面两种情况,每个X周围两个格子不能再放X了,因为放完之后,对手下一轮再放一个就输了. 最后当“ ...
- UVA 10561 - Treblecross(博弈SG函数)
UVA 10561 - Treblecross 题目链接 题意:给定一个串,上面有'X'和'.',能够在'.'的位置放X.谁先放出3个'X'就赢了,求先手必胜的策略 思路:SG函数,每一个串要是上面有 ...
- HDU5795A Simple Nim SG定理
A Simple Nim Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Tota ...
- HDU5724 Chess(SG定理)
题目 Source http://acm.hdu.edu.cn/showproblem.php?pid=5724 Description Alice and Bob are playing a spe ...
- HDU 1851 (巴什博奕 SG定理) A Simple Game
这是由n个巴什博奕的游戏合成的组合游戏. 对于一个有m个石子,每次至多取l个的巴什博奕,这个状态的SG函数值为m % (l + 1). 然后根据SG定理,合成游戏的SG函数就是各个子游戏SG函数值的异 ...
- SG函数和SG定理【详解】
在介绍SG函数和SG定理之前我们先介绍介绍必胜点与必败点吧. 必胜点和必败点的概念: P点:必败点,换而言之,就是谁处于此位置,则在双方操作正确的情况下必败. N点:必胜点 ...
- 简单易懂的博弈论讲解(巴什博弈、尼姆博弈、威佐夫博弈、斐波那契博弈、SG定理)
博弈论入门: 巴什博弈: 两个顶尖聪明的人在玩游戏,有一堆$n$个石子,每次每个人能取$[1,m]$个石子,不能拿的人输,请问先手与后手谁必败? 我们分类讨论一下这个问题: 当$n\le m$时,这时 ...
- 【bzoj3576】[Hnoi2014]江南乐 博弈论+SG定理+数学
题目描述 两人进行 $T$ 轮游戏,给定参数 $F$ ,每轮给出 $N$ 堆石子,先手和后手轮流选择石子数大于等于 $F$ 的一堆,将其分成任意(大于1)堆,使得这些堆中石子数最多的和最少的相差不超过 ...
- SG函数&&SG定理
必胜点和必败点的概念: P点:必败点,换而言之,就是谁处于此位置,则在双方操作正确的情况下必败. N点:必胜点,处于此情况下,双方操作均正确的情况下必胜. 必胜点和必败点的 ...
随机推荐
- COGS 696. [IOI1996][USACO 2.3] 最长前缀
★ 输入文件:prefix.in 输出文件:prefix.out 简单对比时间限制:1 s 内存限制:128 MB 描述 USACO 2.3.1 IOI96 在生物学中,一些生物的结构 ...
- vijos 1034 家族(水题日常)
描述 若某个家族人员过于庞大,要判断两个是否是亲戚,确实还很不容易,现在给出某个亲戚关系图,求任意给出的两个人是否具有亲戚关系. 规定:x和y是亲戚,y和z是亲戚,那么x和z也是亲戚.如果x,y是亲戚 ...
- java日期操作的工具类时间格式的转换
package cn.itcast.oa.util; import java.text.ParseException; import java.text.SimpleDateFormat;import ...
- webStorm Ctrl+s 自动格式化 然后 保存 用宏命令
使用WebStorm的Macros宏指令,实现保存的同时格式化代码,并跳至行尾 https://blog.csdn.net/gyz718/article/details/70556188
- ucosii(2.89)mbox 应用要点
OSMboxCreate(void *msg) 当创建一个mbox时候,消息邮箱允许(任务或者中断)向其他一个或者几个任务发送消息.初始化msg指向消息邮箱中的消息. void*OSMboxP ...
- 函数的参数是函数,函数中Ajax返回的回调函数中的函数运行
调用函数 checkAjax('addrinfo',formdata,vzxcv); 函数checkAjax function checkAjax(url,formdata,call_back){ / ...
- ios之UIButoon
第一.UIButton的定义 UIButton *button=[[UIButton buttonWithType:(UIButtonType); 能够定义的button类型有以下6种, typede ...
- 响应式web设计视图工具及插件总结----20150113
响应式web设计可以说火不火是迟早的,下面就对于最开始的视口调试的方法汇总,希望有好的方法大家一起交流. 1.火狐:从Firefox升级到29.0之后就不直接支持Firesizer了. 先安装Add- ...
- 167. Two Sum II - Input array is sorted@python
Given an array of integers that is already sorted in ascending order, find two numbers such that the ...
- C语言实现链表及其操作
#include <stdio.h> #include <stdlib.h> //定义节点 typedef struct Node { int data; struct Nod ...