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点:必胜点,处于此情况下,双方操作均正确的情况下必胜. 必胜点和必败点的 ...
随机推荐
- Docker镜像的目录存储讲解
我们成功安装完docker后,执行命令行sudo docker run hello-world, 如果是第一次执行,则会从远程拉取hello-world的镜像到本地,然后运行,显示hello worl ...
- CPP-基础:关于内存分配
1:c中的malloc和c++中的new有什么区别 (1)new.delete 是操作符,可以重载,只能在C++中使用.(2)malloc.free是函数,可以覆盖,C.C++中都可以使用.(3)ne ...
- BestCoder Round#15 1001-Love
http://acm.hdu.edu.cn/showproblem.php?pid=5082 Love Time Limit: 2000/1000 MS (Java/Others) Memory ...
- luogu愚人节比赛划水记
先放链接:愚人节比赛 说好的 不毒瘤 呢?题目都太神奇了吧! 管理员的脑洞orz T1 这个可以说是蒙数据蒙出来的,直接输出"0",AC T2 本机房dalao成功发现" ...
- shell脚本,批量创建10个系统帐号并设置密码为随机8位字符串。
[root@localhost wyb]# cat user10.sh #!/bin/bash #批量创建10个系统帐号wangyb01-wangyb10并设置密码(密码为随机8位字符串). > ...
- 新浪oAuth授权
首先要拥有一个微博账号 第一步 成为新浪开发者 1.登录微博开发者界面 open.weibo.com 2. 点击登录 点击移动应用,创建应用 3.需要进行开发者认证,填写个人信息及邮箱认证,等 ...
- ios 自定义RadioButton
1 前言 众所周知在IOS中没有单选按钮这一控件,今天我们来学习一下简单的单选控件.类似与Web中的radio表单元素. 2 详述 本控件单纯的利用按钮控件和NSObject的respondsToSe ...
- 学习笔记之30个常用的maven命令
maven 命令的格式为 mvn [plugin-name]:[goal-name],可以接受的参数如下, -D 指定参数,如 -Dmaven.test.skip=true 跳过单元测试: -P 指定 ...
- (15)zabbix ODBC数据库监控
概述 ODBC监控对应于Zabbix Web管理端中的Database monitor监控项类型. ODBC是用于访问数据库管理系统(DBMS)的C语言中间件API.ODBC由Microsoft开发, ...
- Linux内核——进程管理之CFS调度器(基于版本4.x)
<奔跑吧linux内核>3.2笔记,不足之处还望大家批评指正 建议阅读博文https://www.cnblogs.com/openix/p/3262217.html理解linux cfs调 ...