首先将棋盘黑白染色,不妨令空格处为黑色。那么移动奇数次后空格一定处于白色格子,偶数次后空格一定处于黑色格子。所以若有某个格子的棋子颜色与棋盘颜色不同,这个棋子就是没有用的。并且空格与某棋子交换后,棋子所在的格子改变使得该棋子与棋盘颜色不同,那么该棋子也会变为无用棋子。那么问题变为空格在棋盘上黑白格子交替移动,棋盘上有障碍物,走过的格子不能再走,不能移动者输。

  显然这是一个二分图博弈。如果所有的最大匹配都包含起点,先手必胜,因为每次只需要沿匹配边走即可,由增广路定理不会出现没边走的情况。否则后手必胜,因为一旦起点不在最大匹配中,走了一条边后后手变成先手,所达点一定在(不包含起点的)最大匹配中。那么每次我们只需要判断空格位置是否处于剩余图的所有最大匹配中,也即判断删除该点后最大匹配是否会减少。这只需要从被删除点原本的匹配点出发找增广路。判断完每次操作后是否处于必胜态后只要看是否从必胜态走到了必胜态即可。

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
#define N 42
char getc(){char c=getchar();while (c==||c==||c==) c=getchar();return c;}
int gcd(int n,int m){return m==?n:gcd(m,n%m);}
int read()
{
int x=,f=;char c=getchar();
while (c<''||c>'') {if (c=='-') f=-;c=getchar();}
while (c>=''&&c<='') x=(x<<)+(x<<)+(c^),c=getchar();
return x*f;
}
int n,m,k,X,Y,a[N][N],p[N*N],match[N*N],id[N][N],cnt,t,ans;
bool flag[N*N],tag[N*N],win[];
int wx[]={,,,-},wy[]={,-,,};
struct data{int to,nxt;
}edge[N*N<<];
void addedge(int x,int y){t++;edge[t].to=y,edge[t].nxt=p[x],p[x]=t;}
bool hungary(int k)
{
for (int i=p[k];i;i=edge[i].nxt)
if (!flag[edge[i].to]&&!tag[edge[i].to])
{
int x=edge[i].to;
flag[x]=;
if (!match[x]||!tag[match[x]]&&hungary(match[x]))
{
match[x]=k,match[k]=x;
return ;
}
}
return ;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("bzoj2437.in","r",stdin);
freopen("bzoj2437.out","w",stdout);
const char LL[]="%I64d\n";
#else
const char LL[]="%lld\n";
#endif
n=read(),m=read();
for (int i=;i<=n;i++)
for (int j=;j<=m;j++)
{
char c=getc();
a[i][j]=c=='O';
if (c=='.') X=i,Y=j;
}
for (int i=;i<=n;i++)
for (int j=;j<=m;j++)
for (int k=;k<;k++)
if (i+wx[k]>=&&i+wx[k]<=n&&j+wy[k]>=&&j+wy[k]<=m&&
(abs(i-X)+abs(j-Y)&)==a[i][j]&&(abs(i+wx[k]-X)+abs(j+wy[k]-Y)&)==a[i+wx[k]][j+wy[k]])
{
if (!id[i][j]) id[i][j]=++cnt;if (!id[i+wx[k]][j+wy[k]]) id[i+wx[k]][j+wy[k]]=++cnt;
addedge(id[i][j],id[i+wx[k]][j+wy[k]]),addedge(id[i+wx[k]][j+wy[k]],id[i][j]);
}
for (int i=;i<=cnt;i++)
if (!match[i]) memset(flag,,sizeof(flag)),hungary(i);
tag[id[X][Y]]=;
if (match[id[X][Y]])
{
memset(flag,,sizeof(flag));
match[match[id[X][Y]]]=;
win[]=!hungary(match[id[X][Y]]);
}
int k=read()<<;
for (int i=;i<=k;i++)
{
int x=read(),y=read();
tag[id[x][y]]=;
if (match[id[x][y]])
{
memset(flag,,sizeof(flag));
match[match[id[x][y]]]=;
win[i]=!hungary(match[id[x][y]]);
}
}
int tot=;
for (int i=;i<k;i+=) if (win[i]&&win[i+]) tot++;
cout<<tot<<endl;
for (int i=;i<k;i+=) if (win[i]&&win[i+]) printf("%d\n",(i>>)+);
return ;
}

BZOJ2437 NOI2011兔兔与蛋蛋(二分图匹配+博弈)的更多相关文章

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

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

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

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

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

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

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

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

  5. 博弈论(二分图匹配):NOI 2011 兔兔与蛋蛋游戏

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

  6. 2437: [Noi2011]兔兔与蛋蛋 - BZOJ

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

  7. NOI2011 兔兔与蛋蛋游戏

    http://www.lydsy.com/JudgeOnline/problem.php?id=2437 这道题真是极好的. 75分做法: 搜索. 出题人真的挺良心的,前15个数据点的范围都很小,可以 ...

  8. 【LOJ】#2447. 「NOI2011」兔兔与蛋蛋的游戏

    题解 对于75分来说,操作肯定不会成环,可以暴搜 看成空格在移动,空格移动到原来的位置肯定经历了偶数个格子,但是操作的人是两个不同的人,所以肯定不会成环 对于满分做法,要找到一种更好的方式判先手是否会 ...

  9. bzoj 2437 [Noi2011]兔子和鸡蛋 [二分图匹配]

    叙述性说明 这些日子.兔子和蛋像一个新的棋盘游戏. 这场比赛是在 n 行 m 在船上进行列. 前,棋盘上有一 个格子是空的,其他的格子中都放置了一枚棋子,棋子或者是黑色,或者是白色. 每一局游戏总是兔 ...

随机推荐

  1. python核心编程2 第十三章 练习

    13-3.对类进行定制.写一个类,用来将浮点型值转换为金额. class MoneyFmt(object): def __init__(self, value=0.0, flag='-'): self ...

  2. centos下安装docker以及docker-composer

    背景 docker已经出来了很久,而我一直想混迹到docker大军中进行冲锋陷阵,恰逢公司项目的需要,因此今天玩了一把docker的安装.使用Docker 一键部署 LNMP+Redis 环境 事先准 ...

  3. 处理laravel表单提交默认将空值转为null的问题

    比如表单提交,如果我们提交了这个字段,但是这个字段为空字符串.在Laravel中会自动转义成Null. 处理这个问题,直到找到中间件\vendor\laravel\framework\src\Illu ...

  4. Linux命令备忘录: jobs 显示Linux中的任务列表及任务状态命令

    Linux jobs命令用法详解:显示Linux中的任务列表及任务状态命令 jobs命令用于显示Linux中的任务列表及任务状态,包括后台运行的任务.该命令可以显示任务号及其对应的进程号.其中,任务号 ...

  5. C# 实现窗口无边框,可拖动效果

    #region 无边框拖动效果 [DllImport("user32.dll")]//拖动无窗体的控件 public static extern bool ReleaseCaptu ...

  6. maven之package与install的区别

    mvn clean package 先看命令的执行过程 mvn clean install 同样先看执行过程 mvn clean package依次执行了clean.resources.compile ...

  7. phpMyAdmin出现错误 Access denied for user 'root'@'localhost' (using password: NO)

    今天安装wmpp,之后启动后点击phpMyAdmin 报拒绝连接错误:#1045 - Access denied for user 'root'@'localhost' (using password ...

  8. c/c++容器操作

    C++中的容器大致可以分为两个大类:顺序容器和关联容器.顺序容器中包含有顺序容器适配器. 顺序容器:将单一类型元素聚集起来成为容器,然后根据位置来存储和访问这些元素.主要有vector.list.de ...

  9. shell -- if参数用法

    一.概要1.if与[之间要有空格2.[]与判断条件之间也必须有空格3.]与:之间不能有空格 二.对字符串的判断1.if [ str1=str2 ];then fi  ----当两个字符串相同时返回真2 ...

  10. java冒泡算法

    public static void maopao() { int temp; int[] values = {2, 34, 0, 245}; for (int i = 0; i < value ...