Description

Input

输入的第一行包含两个正整数 n、m。
接下来 n行描述初始棋盘。其中第i 行包含 m个字符,每个字符都是大写英文字母"X"、大写英文字母"O"或点号"."之一,分别表示对应的棋盘格中有黑色棋子、有白色棋子和没有棋子。其中点号"."恰好出现一次。
接下来一行包含一个整数 k(1≤k≤1000) ,表示兔兔和蛋蛋各进行了k次操作。
接下来 2k行描述一局游戏的过程。其中第 2i – 1行是兔兔的第 i 次操作(编号为i的操作) ,第2i行是蛋蛋的第i次操作。每个操作使用两个整数x,y来描述,表示将第x行第y列中的棋子移进空格中。
输入保证整个棋盘中只有一个格子没有棋子, 游戏过程中兔兔和蛋蛋的每个操作都是合法的,且最后蛋蛋获胜。

Output

输出文件的第一行包含一个整数r,表示兔兔犯错误的总次数。
接下来r 行按递增的顺序给出兔兔“犯错误”的操作编号。其中第 i 行包含一个整数ai表示兔兔第i 个犯错误的操作是他在游戏中的第 ai次操作。
1 ≤n≤ 40, 1 ≤m≤ 40

Sample Input

样例一:
1 6
XO.OXO
1
1 2
1 1
样例二:
3 3
XOX
O.O
XOX
4
2 3
1 3
1 2
1 1
2 1
3 1
3 2
3 3
样例三:
4 4
OOXX
OXXO
OO.O
XXXO
2
3 2
2 2
1 2
1 3

Sample Output

样例一:
1
1
样例二:
0
样例三:
2
1
2

样例1对应图一中的游戏过程
样例2对应图三中的游戏过程

HINT

  这道题很好,思维巧妙又不难打。题解直接引用maijing的:

二分图匹配。

性质1 空格移动的路径一定不会自交。

记出发格子为A_0,第i步到达的格子为A_i。

虽然第一次相交的点不一定是A_0,但不失一般性,假设走了n步之后第一次与A_0相交,即走过了A_0,A_1,A_2,...,A_n-1,A_n。

因为每次是移动是上下左右四个方向之一,因为又回到出发点,所以有多少次向上走就有多少次向下走,有多少次向左走就有多少次向右走,所以n是偶数。

我们发现,第奇数次移动的为先手,即A_1,A_3,A_5,...,A_n-1;第偶数次移动的为后手,即A_0,A_2,A_4,...,A_n。

因为又回到了出发地,所以A_1和A_n是同一个棋子,但是2个人同时移动了这个棋子,矛盾,所以空格移动的路径一定不会自交。

不妨将刚开始时空格所在的格子看成黑色 那么空格移动的路径一定是黑白相间的。

建立二分图,左边为黑色,右边为白色,之间有相邻关系的连边。兔兔是从左边走到右边,蛋蛋是从右边走到左边。

性质2 当且仅当最大匹配一定覆盖空格所在的结点时,兔兔必胜;否则蛋蛋必胜。

(1)如果存在一个最大匹配不覆盖空格所在的结点,蛋蛋必胜。

如图实线是匹配边,虚线是非匹配边,空格所在的结点为start。

因为最大匹配不覆盖空格所在的结点start,所以兔兔只能沿着某一条非匹配边到右边,不妨设到了v(如果没有到右边的没走过的非匹配边,那么兔兔输了)。

v一定是被覆盖的(不然start就可以连到v,就不是最大匹配了)。

蛋蛋可以沿着覆盖v的匹配边到左边的u。

也就是说,当兔兔到了右边后,蛋蛋一定有路径回到左边;但是当蛋蛋到了左边后,兔兔不一定有路径到右边。

所以如果存在一个最大匹配不覆盖空格所在的结点,蛋蛋必胜。

(2)如果最大匹配一定覆盖空格所在的结点时,兔兔必胜。

我们可以类似(1)中进行分析。

虽然这道题不是问我们谁必胜,但这给我们接下来提供了一种思考方法。

现在兔兔走第1步,从start走到v。

首先我们根据性质2,判断兔兔是否必胜,就是判断使用start点和不使用start点时的最大匹配是否相等,如果不相等,说明最大匹配一定覆盖start点,兔兔必胜。

然后强行覆盖start到v的边。

我们要这时候蛋蛋要从左边往右边走,我们要判断蛋蛋是否必胜。

如果蛋蛋能够走到兔兔的一个必败态,那么蛋蛋必胜。

根据性质2,我们得出结论:在start到v的边一定被覆盖的情况下,当且仅当与v有边相连的所有点都一定被最大匹配覆盖,蛋蛋必输;否则蛋蛋必胜。

所以如果在某种最大匹配方案中,与v相连的某个点没有被最大匹配覆盖,那么蛋蛋必胜。

如图,与v相连的点为a,b,c,在图示的最大匹配方案中,c没有被最大匹配覆盖,所以蛋蛋必胜。

接下来读入蛋蛋第1步走的格子,start变成为蛋蛋第1步走的格子。

然后类似做就可以了。

  然后代码极简单。

 #include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const int N=;
const int M=;
int cnt,cntX,cntO;
int fir[N],to[M],nxt[M];
int match[N],vis[N],ban[N],id[][],ans[];
char map[][];
int n,m,px,py;
int tx[]={,,,-};
int ty[]={,,-,};
void addedge(int a,int b){
nxt[++cnt]=fir[a];to[fir[a]=cnt]=b;
} bool DFS(int x){
for(int i=fir[x];i;i=nxt[i])
if(!vis[to[i]]&&!ban[to[i]]){vis[to[i]]=;
if(!match[to[i]]||DFS(match[to[i]]))
{match[match[to[i]]=x]=to[i];return true;}
}
return false;
} int main(){
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++)
scanf("%s",map[i]+);
for(int i=;i<=n;i++)
for(int j=;j<=m;j++){
if(map[i][j]=='.')
map[i][j]='X',px=i,py=j;
if(map[i][j]=='O')
id[i][j]=++cntO;
else if(map[i][j]=='X')
id[i][j]=++cntX;
}
for(int i=;i<=n;i++)
for(int j=;j<=m;j++)
if(map[i][j]=='O')
id[i][j]+=cntX; for(int i=;i<=n;i++)
for(int j=;j<=m;j++)if(id[i][j]){
for(int k=;k<;k++){
int gx=tx[k]+i,gy=ty[k]+j;
if(map[gx][gy]!=map[i][j])
addedge(id[i][j],id[gx][gy]);
}
}
for(int i=;i<=cntX;i++)if(!match[i])
{memset(vis,,sizeof(vis));DFS(i);} int k;scanf("%d",&k);
for(int i=;i<=*k;i++){
int x;ban[x=id[px][py]]=;
if(match[x]){int y=match[x];
memset(vis,,sizeof(vis));
match[x]=match[y]=;
ans[i]=DFS(y)^;
}
scanf("%d%d",&px,&py);
}
int ret=;
for(int i=;i<=k;i++)
ret+=ans[i*]&ans[i*-];
printf("%d\n",ret);
for(int i=;i<=k;i++)
if(ans[i*]&ans[i*-])
printf("%d\n",i);
return ;
}

博弈论(二分图匹配):NOI 2011 兔兔与蛋蛋游戏的更多相关文章

  1. BZOJ2437 [Noi2011]兔兔与蛋蛋 【博弈论 + 二分图匹配】

    题目链接 BZOJ2437 题解 和JSOI2014很像 只不过这题动态删点 如果我们把空位置看做\(X\)的话,就会发现我们走的路径是一个\(OX\)交错的路径 然后将图二分染色,当前点必胜,当且仅 ...

  2. BZOJ1443 [JSOI2009]游戏Game 【博弈论 + 二分图匹配】

    题目链接 BZOJ1443 题解 既然是网格图,便可以二分染色 二分染色后发现,游戏路径是黑白交错的 让人想到匹配时的增广路 后手要赢[指移动的后手],必须在一个与起点同色的地方终止 容易想到完全匹配 ...

  3. 二分图匹配——p3386 p2071 p2319 p1129(矩阵游戏)

    ---恢复内容开始--- 二分图,就是给你一个图,可以将点分为两部分,每一部分的点都能唯一映射到另一个集合里,也就是有连边: 注:以下转自 http://blog.csdn.net/dark_scop ...

  4. 【BZOJ2437】【NOI2011】兔兔与蛋蛋(博弈论,二分图匹配)

    [BZOJ2437][NOI2011]兔兔与蛋蛋(博弈论,二分图匹配) 题面 BZOJ 题解 考虑一下暴力吧. 对于每个状态,无非就是要考虑它是否是必胜状态 这个直接用\(dfs\)爆搜即可. 这样子 ...

  5. 【bzoj2437】[Noi2011]兔兔与蛋蛋 二分图最大匹配+博弈论

    Description Input 输入的第一行包含两个正整数 n.m. 接下来 n行描述初始棋盘.其中第i 行包含 m个字符,每个字符都是大写英文字母"X".大写英文字母&quo ...

  6. 【BZOJ 2437】 2437: [Noi2011]兔兔与蛋蛋 (博弈+二分图匹配**)

    未经博主同意不得转载 2437: [Noi2011]兔兔与蛋蛋 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 693  Solved: 442 Des ...

  7. bzoj 2437[Noi2011]兔兔与蛋蛋 黑白染色二分图+博弈+匈牙利新姿势

    noi2011 兔兔与蛋蛋 题目大意 直接看原题吧 就是\(n*m\)的格子上有一些白棋和一些黑棋和唯一一个空格 兔兔先手,蛋蛋后手 兔兔要把与空格相邻的其中一个白棋移到空格里 蛋蛋要把与空格相邻的其 ...

  8. FZU - 2039 Pets (二分图匹配 2011年全国大学生程序设计邀请赛(福州))

    Description Are you interested in pets? There is a very famous pets shop in the center of the ACM ci ...

  9. 【BZOJ1443】游戏(二分图匹配,博弈论)

    [BZOJ1443]游戏(二分图匹配,博弈论) 题面 BZOJ 题解 很明显的二分图博弈问题. 发现每次移动一定是从一个黑点到达一个白点,或者反过来. 所以可以对于棋盘进行染色然后连边. 考虑一下必胜 ...

随机推荐

  1. 黑马程序员-IO(二)

    ------Java培训.Android培训.iOS培训..Net培训.期待与您交流! ------- 装饰设计模式: 当想要对已有对象进行功能增强时.可以定义类,将已经有的类传入,基于已经有的功能, ...

  2. asp.net mvc5 设置Area下的为启动页

    只需修改App_Start文件夹下RouteConfig中RegisterRoutes方法 public static void RegisterRoutes(RouteCollection rout ...

  3. CSS制作hover下划线动画

    .demo1{ position: relative; text-decoration: none; font-size: 20px; color: #333; } .demo1:before{ co ...

  4. 使用for循环嵌套实现乘法口诀表

    九九乘法表的实现: package com.liaojianya.chapter1; /** * This program demonstrates the way of using * for-lo ...

  5. 【转】.Net中通过反射技术的应用----插件程序的开发入门

    转自:http://www.cnblogs.com/winloa/archive/2012/03/25/2416355.html .Net中通过反射技术的应用----插件程序的开发入门 再开始之前,先 ...

  6. js快速排序法

    var quickSort = function(arr) { if (arr.length <= 1) { return arr; } var pivotIndex = Math.floor( ...

  7. JavaScript学习总结【8】、面向对象编程

    1.什么是面向对象编程 要理解面向对象,得先搞清楚什么是对象,首先需要明确一点这里所说的对象,不是生活中的搞男女朋友对象,面向对象就是面向着对象,换在代码中,就是一段代码相中了另一段代码,自此夜以继日 ...

  8. Apache 支持PHP

    ①加载PHP模块到Apache中: LoadModule php5_module "d:\php5\php5apache2_2.dll"   ②加入识别扩展名为.php文件(也可以 ...

  9. hierarchyviewer偶然不能使用的解决方法

    在DDMS的device中可以看到设备,并显示可以debug的状态,可以看到不显示进程的信息,但是hierarchyviewer也却不显示各个Window. 在控制台的打印信息如下: - hierar ...

  10. sql server 查询表某个字段不重复数据

    SELECT TOP (500) ID, Personname, Personcode, Telphone, Fraction into temp3 FROM Records AS a WHERE ( ...