[NOI2011] 兔兔与蛋蛋游戏题解
题目描述
这些天,兔兔和蛋蛋喜欢上了一种新的棋类游戏。
这个游戏是在一个 nn 行 mm 列的棋盘上进行的。游戏开始之前,棋盘上有一个格子是空的,其它的格子中都放置了一枚棋子,棋子或者是黑色,或者是白色。
每一局游戏总是兔兔先操作,之后双方轮流操作,具体操作为:
- 兔兔每次操作时,选择一枚与空格相邻的白色棋子,将它移进空格。
- 蛋蛋每次操作时,选择一枚与空格相邻的黑色棋子,将它移进空格。
第一个不能按照规则操作的人输掉游戏。为了描述方便,下面将操作“将第x行第y列中的棋子移进空格中”记为 M(x,y)M(x,y)。
例如下面是三个游戏的例子。
最近兔兔总是输掉游戏,而且蛋蛋格外嚣张,于是兔兔想请她的好朋友——你——来帮助她。她带来了一局输给蛋蛋的游戏的实录,请你指出这一局游戏中所有她“犯错误”的地方。
注意:
- 两个格子相邻当且仅当它们有一条公共边。
- 兔兔的操作是“犯错误”的,当且仅当,在这次操作前兔兔有必胜策略,而这次操作后蛋蛋有必胜策略。
输入格式
输入的第一行包含两个正整数 n,mn,m。
接下来 nn 行描述初始棋盘。其中第 ii 行包含 mm 个字符,每个字符都是大写英文字母 X
、大写英文字母 O
或点号 .
之一,分别表示对应的棋盘格中有黑色棋子、有白色棋子和没有棋子。其中点号 .
恰好出现一次。
接下来一行包含一个整数 kk(1\leq k\leq 10001≤k≤1000) ,表示兔兔和蛋蛋各进行了 kk 次操作。
接下来 2k2k 行描述一局游戏的过程。其中第 2i – 12i–1 行是兔兔的第 ii 次操作(编号为 ii 的操作) ,第 2i2i 行是蛋蛋的第 ii 次操作。每个操作使用两个整数 x,yx,y 来描述,表示将第 xx 行第 yy 列中的棋子移进空格中。
输入保证整个棋盘中只有一个格子没有棋子, 游戏过程中兔兔和蛋蛋的每个操作都是合法的,且最后蛋蛋获胜。
输出格式
输出文件的第一行包含一个整数 rr,表示兔兔犯错误的总次数。
接下来 rr 行按递增的顺序给出兔兔“犯错误”的操作编号。其中第 ii 行包含一个整数 a_iai 表示兔兔第 ii 个犯错误的操作是他在游戏中的第 a_iai 次操作。
输入输出样例
输入 #1复制
1 6 XO.OXO 1 1 2 1 1
输出 #1复制
1 1
输入 #2复制
3 3 XOX O.O XOX 4 2 3 1 3 1 2 1 1 2 1 3 1 3 2 3 3
输出 #2复制
0
输入 #3复制
4 4 OOXX OXXO OO.O XXXO 2 3 2 2 2 1 2 1 3
输出 #3复制
2 1 2
说明/提示
对于 100\%100% 的数据,1\leq n\leq 401≤n≤40,1 \leq m\leq 401≤m≤40,1\leq k\leq 10001≤k≤1000。
测试点编号 | nn | mm |
---|---|---|
1,21,2 | n=1n=1 | 1\leq m\leq 201≤m≤20 |
33 | n=3n=3 | m=4m=4 |
4,54,5 | n=4n=4 | m=4m=4 |
6,76,7 | n=4n=4 | m=5m=5 |
88 | n=3n=3 | m=7m=7 |
9\sim 149∼14 | n=2n=2 | 1\leq m\leq 401≤m≤40 |
15,1615,16 | 1\leq n\leq 161≤n≤16 | 1\leq m\leq 161≤m≤16 |
17\sim 2017∼20 | 1\leq n\leq 401≤n≤40 | 1\leq m\leq 401≤m≤40 |
前置知识:
- 对于二分图博弈,先手如果率先落入最大匹配的点x中,那么后手只需要选择与x匹配的点y走即可,走到最后先手必败;
- 如果是完全匹配,那么先手无论落子何处,均率先落入最大匹配点,先手必败;
- 如果不是完全匹配,先手选择非最大匹配点x落子,那么后手无论落子何处,都是最大匹配中的某点y, 因为如果y不是最大匹配的点, 则x到y形成增广路,最大匹配的边数还可以加1,导致矛盾;进而, 后手率先落入最大匹配的点中,先手有必胜策略;
本题策略:
- 把棋子的移动视为空格的移动,那么兔兔先手移动空格到白子处,因此可以将空格看作黑色, 黑白染色,建二分图;
- 如果在移动空格前,空格处于最大匹配的非必须点,那么移动后必然率先进入最大匹配中,必败,反之有必胜策略;
- 对于K轮游戏,第i轮游戏时空格的位置cur在(sx, sy), 如果cur不在最大匹配中,那么落子后必落入最大匹配, 所以无论怎么落子,必败;
- 如果cur在最大匹配中,且有匹配match[cur]为nxt,那么删掉cur后从nxt跑匈牙利,看nxt是否还能有另外的匹配,如果有 那么cur就不是最大匹配的必须点,有必胜策略,反之仍然必败;对每1轮游戏重复操作,得到每1轮游戏的胜负情况win[i];
- 如何判断兔兔犯了错误?——如果win[i]是必胜,而兔兔走完之后win[i+1]必胜,那么就说明兔兔犯了错;
#include<iostream>
#include<cstring>
using namespace std;
const int N = 50, K = 1005;
int n, m, ans, cnt, tot, head[N*N];
char g[N][N];
int match[N*N], res[K*2], win[K*2];
bool vis[N*N], block[N*N], color[N][N];
int dx[4] = {1, 0, 0, -1};
int dy[4] = {0, 1, -1, 0};
struct node
{int to, nxt;
}edge[N*N*2*4]; //每个点连4个方向,双向边 void addedge(int s, int e)
{cnt++;edge[cnt].to = e;edge[cnt].nxt = head[s];head[s] = cnt;return ;
}bool dfs(int x) //匈牙利算法
{for(int i = head[x]; i != 0; i = edge[i].nxt) {int y = edge[i].to;if(block[y] == true) //添加一行屏蔽已删掉的点 continue;if(vis[y] == false) {vis[y] = true;//如果y没有匹配 或者 y的匹配点match[y]能找到一个新的匹配if(match[y] == 0 || dfs(match[y]) == true) {match[y] = x; //y的配对点是xmatch[x] = y; //增加这行代码的原因是为了找最大匹配非必须点return true;}}}return false;
}int get_id(int x, int y)
{return (x-1) * m + y;
} bool check(int x, int y)
{if(x < 1 || x > n || y < 1 || y > m || color[x][y] == false)return false;return true;
}int main()
{//输入 cin >> n >> m;for(int i = 1; i <= n; i++)for(int j = 1; j <= m; j++)cin >> g[i][j]; //迷宫数组 //染色int sx, sy;for(int i = 1; i <= n; i++)for(int j = 1; j <= m; j++){if(g[i][j] == 'O') //将白色的棋子染色 {color[i][j] = true;}else if(g[i][j] == '.') //起点记录,当作黑色对待 {sx = i;sy = j;}}//建图 for(int i = 1; i <= n; i++)for(int j = 1; j <= m; j++){if(color[i][j] == true) //白子跳过 continue;int cur = get_id(i, j); //当前点编号 for(int k = 0; k < 4; k++){int nx = i + dx[k];int ny = j + dy[k];if(check(nx, ny) == false)continue;int nxt = get_id(nx, ny);addedge(cur, nxt); //建边 addedge(nxt, cur); //找最大匹配不需要反边,但是找最大匹配非必须点需要折返跑 }}//匈牙利, 目的是看起点是否落在最大匹配中 for(int i = 1; i <= n; i++)for(int j = 1; j <= m; j++){if(color[i][j] == false)continue;memset(vis, 0, sizeof(vis));int cur = get_id(i, j); if(dfs(cur) == true) ans++;}//输入游戏过程 int k; cin >> k;for(int i = 1; i <= 2*k; i++){int cur = get_id(sx, sy);block[cur] = true; //删掉cur if(match[cur] == 0) //棋子当前不在匹配中,那么下一步会率先走到最大匹配中,必败 win[i] = false;else{int nxt = match[cur];match[cur] = match[nxt] = 0; //删掉cur与 nxt的匹配关系 memset(vis, 0, sizeof(vis)); //跑匈牙利记得清0 vis if(dfs(nxt) == true) //若nxt还能找到匹配,则cur不是最大匹配必须, 那么下一步率先走到最大匹配,必败 win[i] = false;elsewin[i] = true; }cin >> sx >> sy;}//处理输出 for(int i = 1; i <= k; i++) {if(win[2*i-1] == true && win[2*i] == true) //兔兔走之前是有必胜策略,走完蛋蛋有必胜策略 {res[++tot] = i; }}cout << tot << endl;for(int i = 1; i <= tot; i++){cout << res[i] << endl;}return 0;
}
[NOI2011] 兔兔与蛋蛋游戏题解相关推荐
- 【题解】P1971 [NOI2011] 兔兔与蛋蛋游戏
首先可以推出来一个引理:空格不可能在经过几次操作后回到原来的位置. 大概感性证明一下:容易发现这个空格如果想要走成一个环,向上走的次数=向下走的次数,向左走的次数=向右走的次数.那么如果开始是兔兔走的 ...
- 【BZOJ2437】【codevs1949】兔兔与蛋蛋游戏,博弈+二分图匹配
传送门1 传送门2 思路: 关于证明 算是bzoj1443的强化版吧 但我是先写的这道题再写的bzoj1443,所以刚开始比较懵逼 二分图中的点是空格.与空格坐标和的奇偶相同的黑点.坐标和奇偶不同的白 ...
- 2023年玩兔年小游戏《兔兔保卫萝卜战》赢新年祝福「钱兔无量」
PS:粉丝可以免费领源码,私信我或者评论666即可~~~~~~~~ 导读 | 世界杯虽已闭幕,但其带给我们的精彩,仿佛就在昨天,想一想,还是有一种爽劲,不知道大家是否也这样?转眼就到了2023年,今年 ...
- linux 性能测试 antutu,除了安兔兔跑分,还有这6种办法能证明手机强弱
原标题:除了安兔兔跑分,还有这6种办法能证明手机强弱 现在说起手机跑分,已经稀松平常,但早在五年前,很多手机用户根本不知道如何测试手机性能."跑分"这个词汇只会出现在媒体的评测文章 ...
- android 跑分软件,跑分软件安兔兔公布了6月份Android手机性能榜TOP10
看了一下这期的安兔兔Android手机性能TOP10,对于华为来说,打击巨大,搭载麒麟处理器的手机没一款上榜,反观高通,则是疯狂屠榜,从第一名到第十名,都是使用它家骁龙8系列处理器的手机. 昨天国内知 ...
- 十月 android版本分布,安兔兔发布2018年10月份Android手机性能排行榜
汽车行业有金九银十一说,手机行业同样也是如此.在刚刚过去的 10 月份,我们见证了多款国产旗舰手机的发布,包括Mate20 系列.小米MIX3.荣耀Mgaic 2.努比亚X等等,得益于强大的硬件配置, ...
- android 跑分,2018年10月国内Android手机安兔兔跑分性能排行榜
汽车行业有金九银十一说,手机行业同样也是如此.在刚刚过去的10月份,我们见证了多款国产旗舰手机的发布,包括Mate 20系列.小米MIX3.荣耀Mgaic 2.努比亚X等等,得益于强大的硬件配置,这些 ...
- 2018年android手机版本统计,安兔兔发布2018年12月Android手机性能排行榜
今天,安兔兔根据后台统计到的数据,公布了 2018 年 12 月份Android手机性能榜,这份 2018 年的最终榜单有哪些手机能够杀入前十呢?拭目以待吧. 注:本文图表中的安兔兔跑分(v7 版)均 ...
- android 手机 跑分榜,安兔兔跑分最新排行图 2020年4月Android手机性能榜
五一假期刚过,不知道各位朋友休息的如何?在假期后的*工作日,安兔兔根据后台统计到的数据,发布了2020年4月份Android手机性能榜单.和以往一样,本次榜单依然分为旗舰榜单和中端榜单. 本次数据统计 ...
最新文章
- python脚本设置linux环境变量_Linux环境变量export方法与修改文件方法的区别
- 2018全国计算机考试报名入口,北京2018年3月全国计算机等级考试报名入口
- w7计算机无法管理员权限设置,操作权限不够?教你开启Win7管理员帐户
- npm中package.json详解
- Docker查看应用的实际内存
- 【转】C++学习二 vector的用法(使用sort对于vector排序)
- 查看mysql日志post_(转)MySQL 日志组提交
- VueSSR高阶指南
- 计算机网络性能(1)
- 坑爹的RegExp test()
- 小米max刷鸿蒙,小米Max刷recovery教程_小米Max第三方recovery下载
- http_load压力测试步骤
- chrome浏览器最小字体大小限制的解决方案
- leetcode oj java Bulls and Cows
- 人民币大写转阿拉伯数字的java实现
- Vue.js:按键修饰符keyup,keyup.enter,keyup.alt.enter的使用
- tm1650按键处理c语言,求助51C语言X9C系列APP遥控驱动显示TM1650怎么将下面的程序合成...
- 爬虫实例3:Python实时爬取新浪热搜榜
- c# 多种方法调整屏幕亮度
- Submerge 3 for Mac 3.4.6 字幕制作工具 中文破解版下载