NOI2011真题:兔兔与蛋蛋游戏
NOI2011真题:兔兔与蛋蛋游戏
题目描述
这些天,兔兔和蛋蛋喜欢上了一种新的棋类游戏。
这个游戏是在一个 n行 m 列的棋盘上进行的。游戏开始之前,棋盘上有一个格子是空的,其它的格子中都放置了一枚棋子,棋子或者是黑色,或者是白色。
每一局游戏总是兔兔先操作,之后双方轮流操作,具体操作为:
·兔兔每次操作时,选择一枚与空格相邻的白色棋子,将它移进空格。
·蛋蛋每次操作时,选择一枚与空格相邻的黑色棋子,将它移进空格。
第一个不能按照规则操作的人输掉游戏。为了描述方便,下面将操作“将第x行第y列中的棋子移进空格中”记为 M(x,y)M(x,y)。
例如下面是三个游戏的例子。

最近兔兔总是输掉游戏,而且蛋蛋格外嚣张,于是兔兔想请她的好朋友——你——来帮助她。她带来了一局输给蛋蛋的游戏的实录,请你指出这一局游戏中所有她“犯错误”的地方。
注意:
·两个格子相邻当且仅当它们有一条公共边。
·兔兔的操作是“犯错误”的,当且仅当,在这次操作前兔兔有必胜策略,而这次操作后蛋蛋有必胜策略。
输入格式
输入的第一行包含两个正整数 n,m。
接下来 n 行描述初始棋盘。其中第 i 行包含 m个字符,每个字符都是大写英文字母 X、大写英文字母 O 或点号 . 之一,分别表示对应的棋盘格中有黑色棋子、有白色棋子和没有棋子。其中点号 . 恰好出现一次。
接下来一行包含一个整数 k(1≤k≤1000) ,表示兔兔和蛋蛋各进行了 k 次操作。
接下来 2k 行描述一局游戏的过程。其中第 2i – 1 行是兔兔的第 i 次操作(编号为 i 的操作) ,第 2i 行是蛋蛋的第 i 次操作。每个操作使用两个整数 x,y 来描述,表示将第 x 行第 y列中的棋子移进空格中。
输入保证整个棋盘中只有一个格子没有棋子, 游戏过程中兔兔和蛋蛋的每个操作都是合法的,且最后蛋蛋获胜。
输出格式
输出文件的第一行包含一个整数 r,表示兔兔犯错误的总次数。
接下来 r行按递增的顺序给出兔兔“犯错误”的操作编号。其中第 i 行包含一个整数ai表示兔兔第 i 个犯错误的操作是他在游戏中的第 ai次操作。
输入样例:
1 6
XO.OXO
1
1 2
1 1
输出样例:
1
1
说明提示:

解法:
知识:二分图,博弈论,深度优先搜索
先审清楚题意。A 一步走错的判定:A 走这步之前,A先手采用最优策略必胜;A 走这步之后,B先手采用最优策略必胜。
判断的过程:强制当前点不选,如果它的匹配点仍然能找到新的匹配点,说明有一种最大匹配不包含它,自然它就不是 一定 在最大匹配中。
代码:
#include<bits/stdc++.h>
using namespace std;
const int MAXN=41,MAXS=1601,MAXK=1001;
int n,m,dx[]={0,0,1,-1},dy[]={1,-1,0,0};
int tar[MAXS];
bool vis[MAXS],win[MAXK];
bool bel[MAXN][MAXN],col[MAXN][MAXN],del[MAXS];
vector <int> edge[MAXS],src;
inline int id(int x,int y) {
if(x<1||x>n||y<1||y>m||bel[x][y]!=col[x][y]) return -1;
return (x-1)*m+y;
}
inline bool match(int p) {
if(del[p]) return false;
for(int x:edge[p]) {
if(vis[x]||del[x]) continue;
vis[x]=true;
if(tar[x]==-1||match(tar[x])) {
tar[x]=p;
return true;
}
}
return false;
}
inline int MM() {
int ret=0;
memset(tar,-1,sizeof(tar));
for(int x:src) {
memset(vis,false,sizeof(vis));
if(match(x)) ++ret;
}
return ret;
}
signed main() {
int kx,ky;
cin>>n>>m;
for(int i=1;i<=n;++i) {
for(int j=1;j<=m;++j) {
char ch;
cin>>ch;
if(ch=='.') kx=i,ky=j,bel[i][j]=true;
else bel[i][j]=(ch=='X');
}
}
for(int i=1;i<=n;++i) for(int j=1;j<=m;++j) col[i][j]=((i+j)%2==(kx+ky)%2);
for(int i=1;i<=n;++i) {
for(int j=1;j<=m;++j) {
if(bel[i][j]&&col[i][j]) {
src.push_back(id(i,j));
for(int k:{0,1,2,3}) {
int x=i+dx[k],y=j+dy[k];
if(id(x,y)!=-1) {
edge[id(i,j)].push_back(id(x,y));
}
}
}
}
}
int stdv=MM(),k;
del[id(kx,ky)]=true;
int tmpv=MM();
win[1]=tmpv!=stdv;
stdv=tmpv;
scanf("%d",&k);
vector <int> ans;
for(int i=1;i<=k;++i) {
int tx,ty;
scanf("%d%d",&tx,&ty);
del[id(tx,ty)]=true;
tmpv=MM();
win[i*2]=tmpv!=stdv;
stdv=tmpv;
if(win[i*2]&&win[i*2-1]) ans.push_back(i);
scanf("%d%d",&tx,&ty);
del[id(tx,ty)]=true;
tmpv=MM();
win[i*2+1]=tmpv!=stdv;
stdv=tmpv;
}
printf("%d\n",(int)ans.size());
for(int p:ans) printf("%d\n",p);
return 0;
}
NOI2011真题:兔兔与蛋蛋游戏的更多相关文章
- NOI2011 兔兔与蛋蛋游戏
http://www.lydsy.com/JudgeOnline/problem.php?id=2437 这道题真是极好的. 75分做法: 搜索. 出题人真的挺良心的,前15个数据点的范围都很小,可以 ...
- 【BZOJ 2437】 2437: [Noi2011]兔兔与蛋蛋 (博弈+二分图匹配**)
未经博主同意不得转载 2437: [Noi2011]兔兔与蛋蛋 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 693 Solved: 442 Des ...
- 2437: [Noi2011]兔兔与蛋蛋 - BZOJ
Description Input 输入的第一行包含两个正整数 n.m.接下来 n行描述初始棋盘.其中第i 行包含 m个字符,每个字符都是大写英文字母"X".大写英文字母" ...
- 【BZOJ2437】【NOI2011】兔兔与蛋蛋(博弈论,二分图匹配)
[BZOJ2437][NOI2011]兔兔与蛋蛋(博弈论,二分图匹配) 题面 BZOJ 题解 考虑一下暴力吧. 对于每个状态,无非就是要考虑它是否是必胜状态 这个直接用\(dfs\)爆搜即可. 这样子 ...
- 【bzoj2437】[Noi2011]兔兔与蛋蛋 二分图最大匹配+博弈论
Description Input 输入的第一行包含两个正整数 n.m. 接下来 n行描述初始棋盘.其中第i 行包含 m个字符,每个字符都是大写英文字母"X".大写英文字母&quo ...
- bzoj 2437[Noi2011]兔兔与蛋蛋 黑白染色二分图+博弈+匈牙利新姿势
noi2011 兔兔与蛋蛋 题目大意 直接看原题吧 就是\(n*m\)的格子上有一些白棋和一些黑棋和唯一一个空格 兔兔先手,蛋蛋后手 兔兔要把与空格相邻的其中一个白棋移到空格里 蛋蛋要把与空格相邻的其 ...
- 博弈论(二分图匹配):NOI 2011 兔兔与蛋蛋游戏
Description Input 输入的第一行包含两个正整数 n.m. 接下来 n行描述初始棋盘.其中第i 行包含 m个字符,每个字符都是大写英文字母"X".大写英文字母&quo ...
- 第三届蓝桥杯 c/c++真题
第三届蓝桥杯真题 c/c++ 以下题目我自己也并不是所有的题目都是一次性就能做对或是有结题思路的.有些题目也是经过查证网上相关的资料或是参考了别人的代码和解题思路才做出来的.总的来看,这份题目考了很多 ...
- 蓝桥杯java历年真题及答案整理1~20.md
蓝桥杯java历年真题及答案整理(闭关一个月,呕心沥血整理出来的) 1 算法是这样的,如果给定N个不同字符,将这N个字符全排列,最终的结果将会是N!种.如:给定 A.B.C三个不同的字符,则结果为:A ...
- Noip前的大抱佛脚----Noip真题复习
Noip前的大抱佛脚----Noip真题复习 Tags: Noip前的大抱佛脚 Noip2010 题目不难,但是三个半小时的话要写四道题还是需要码力,不过按照现在的实力应该不出意外可以AK的. 机器翻 ...
随机推荐
- docker-compose部署elastiflow
docker-compose导入导出命令 涉及的命令有export.import.save.load save 命令 docker save [options] images [images...] ...
- MySQL半同步复制源码解析
今天 DBA 同事问了一个问题,MySQL在半同步复制的场景下,当关闭从节点时使得从节点的数量 < rpl_semi_sync_master_wait_for_slave_count时,show ...
- k8s日志架构和基本日志
如果一个容器崩溃了.一个Pod被驱逐了.或者一个节点停机了,您通常仍然需要访问您应用程序的日志.为此,您需要一个生命周期与节点.Pod.容器相对独立的存储空间来存储应用程序日志和系统日志. 此时,我们 ...
- csv->html
seg1=''' <!DOCTYPE HTML>\n<html>\n<body>\n<meta charset=gb> <h2 align=cen ...
- 实验02_Proteus仿真数码管显示报告
一.原理总结 利用两个寄存器 R4 和 R5 来存储两个数码管的显示数字,R4 用来存储前一个数码管显示数字,而 R5 用来存储后一个数码管显示数字,利用左移操作 RLC 取 A 中首位放入 C ...
- Tubian系统无法打开Android子系统的解决方法
打开Konsole,Konsole在程序菜单(左下角Logo)-系统中 输入: sudo nano /var/lib/waydroid/waydroid.cfg 回车 按方向键,把光标移动到[prop ...
- Netty 学习(七):NioEventLoop 对应线程的创建和启动源码说明
Netty 学习(七):NioEventLoop 对应线程的创建和启动源码说明 作者: Grey 原文地址: 博客园:Netty 学习(七):NioEventLoop 对应线程的创建和启动源码说明 C ...
- C字符串和C++中string的区别
在C++中则把字符串封装成了一种数据类型string,可以直接声明变量并进行赋值等字符串操作.以下是C字符串和C++中string的区别: C字符串 string对象(C++) 所需的头文件名称 ...
- C语言在Linux下创建一个僵尸进程
第三章编程题3.12 1.僵尸进程是什么 每一个进程都有一个PCB(进程控制块),其中包含进程执行的状态等一系列信息. 当父进程fork()出一个子进程,子进程执行结束后操作系统会回收子进程使用的内存 ...
- 集训队互测2016Unknown(UOJ191)
题目链接 前面部分和lzz的题解是一样的. 首先将输入点(x,y)变为(-y,x)然后,只需找一个向量与(-y,x)的点积最大,即找一个向量在(-y,x)上的投影最长.此时所有的点都是在x轴上方的,容 ...