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

题面

BZOJ

题解

考虑一下暴力吧。

对于每个状态,无非就是要考虑它是否是必胜状态

这个直接用\(dfs\)爆搜即可。

这样子对于每一次操作,考虑兔兔操作后的状态是否是必胜状态

如果这个状态是必胜状态,并且蛋蛋操作完后的状态是(兔兔的)必败状态

那么这就是一个“犯错误”的操作。

这样暴力可以拿到\(75pts\)

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define ll long long
#define RG register
#define MAX 45
inline int read()
{
RG int x=0,t=1;RG char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=-1,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return x*t;
}
int n,m,X,Y;
char ch[MAX];
int g[MAX][MAX],zt[MAX];
int d[4][2]={1,0,-1,0,0,1,0,-1};
int ans[MAX*MAX],top,Q;
bool dfs(int x,int y,int z)
{
for(int i=0;i<4;++i)
{
int xx=x+d[i][0],yy=y+d[i][1];
if(xx<1||xx>n||yy<1||yy>m||g[xx][yy]!=z)continue;
swap(g[x][y],g[xx][yy]);
if(!dfs(xx,yy,z^1)){swap(g[x][y],g[xx][yy]);return true;}
swap(g[x][y],g[xx][yy]);
}
return false;
}
int main()
{
n=read();m=read();
for(int i=1;i<=n;++i)
{
scanf("%s",ch+1);
for(int j=1;j<=m;++j)
if(ch[j]=='X')g[i][j]=1;
else if(ch[j]=='O')g[i][j]=0;
else if(ch[j]=='.')g[i][j]=2;
}
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
if(g[i][j]==2){X=i;Y=j;break;}
Q=read();
for(int i=1,x,y;i<=Q;++i)
{
x=read(),y=read();
zt[i]=dfs(X,Y,0);
swap(g[x][y],g[X][Y]);
X=x;Y=y;
if(zt[i]&&dfs(X,Y,1))ans[++top]=i;
x=read();y=read();
swap(g[x][y],g[X][Y]);
X=x;Y=y;
}
printf("%d\n",top);
for(int i=1;i<=top;++i)printf("%d\n",ans[i]);
return 0;
}

观察一下基本的事实。

考虑走的方案是否可能出现一个环。

无论环有多大,似乎都是一样的,所以我们就考虑在\(2\times 2\)的方格中移动

初始时空格在\((1,1)\),它和\((1,2)\)交换位置,此时,\((1,1)\)为白

然后\((1,2)\)和\((2,2)\)交换位置,\((1,2)\)为黑

\((2,2)\)和\((2,1)\)交换位置,\((2,2)\)为白

此时如果\((2,1)\)能与\((1,1)\)交换位置,那么\((1,1)\)需要是黑色

但是\((1,1)\)是白色,所以显然不能成环。

对于一个更大的环,无非是长\(+1\)或者宽\(+1\)拓展出来的,每次多走两步,对于黑白没有影响。

既然不能成环,意味着每个点只会被经过一次。

那么,我们可以重新开一下这个过程,可以理解为从空格开始,

走一条路径,路径上黑白相间。

黑白相间?有点像二分图的感觉。每条增广路不就是黑白相间吗?

因为先手的是白格子,所以可以把空格开成黑格子

这样子就是要从这个黑格子这里找一条增广路出去。

再考虑一下胜利的情况,如果先手胜利,那么从黑格子连向了一个白格子

然后找不到增广路了,此时白格子胜。

继续把这个情况向上拓展,我们可以得到。

如果当前点一定在二分图的最大匹配中,那么先手必胜。因为先手始终可以沿着最大匹配的匹配边走,而最大匹配中交错路的数量为奇数条,也就是进行奇数次操作,意味着后手最后无法操作,此时先手必胜。

那么,每次进行判定当前点是否在二分图的最大匹配中,是否一定被选中即可判定先手是否必胜,依次可以计算答案。

至于如何计算当前点是否一定在二分图的最大匹配中?

把当前点给\(ban\)掉,在增广的时候强行不选,然后对其匹配点进行增广,

如果能够找到新的增广路,意为这当前点可以被替代,

否则当前点一定在最大匹配中。

这题好神仙啊

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define ll long long
#define RG register
#define MAX 45
inline int read()
{
RG int x=0,t=1;RG char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=-1,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return x*t;
}
int n,m,X,Y;
char ch[MAX];
int g[MAX][MAX],zt[MAX*MAX];
int d[4][2]={1,0,-1,0,0,1,0,-1};
int ans[MAX*MAX],top,Q;
int bh[MAX][MAX],tot;
struct Line{int v,next;}e[MAX*MAX<<3];
int h[MAX*MAX],cnt=1;
inline void Add(int u,int v){e[cnt]=(Line){v,h[u]};h[u]=cnt++;}
int match[MAX*MAX],tim,vis[MAX*MAX];
bool ban[MAX*MAX];
bool dfs(int u)
{
if(ban[u])return false;
for(int i=h[u];i;i=e[i].next)
if(vis[e[i].v]!=tim&&!ban[e[i].v])
{
vis[e[i].v]=tim;
if(!match[e[i].v]||dfs(match[e[i].v]))
{
match[e[i].v]=u;match[u]=e[i].v;
return true;
}
}
return false;
}
int main()
{
n=read();m=read();
for(int i=1;i<=n;++i)
{
scanf("%s",ch+1);
for(int j=1;j<=m;++j)
if(ch[j]=='X')g[i][j]=1;
else if(ch[j]=='O')g[i][j]=0;
else if(ch[j]=='.')g[i][j]=1,X=i,Y=j;
}
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
bh[i][j]=++tot;
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
if(g[i][j])
for(int k=0;k<4;++k)
{
int x=i+d[k][0],y=j+d[k][1];
if(x<1||x>n||y<1||y>m||g[x][y])continue;
Add(bh[i][j],bh[x][y]);
Add(bh[x][y],bh[i][j]);
}
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
if(g[i][j])++tim,dfs(bh[i][j]);
Q=read();
for(int i=1,id;i<=Q+Q;++i)
{
id=bh[X][Y];ban[id]=true;
if(match[id])
{
int nw=match[id];match[nw]=match[id]=0;
++tim;zt[i]=!dfs(nw);
}
X=read();Y=read();
}
for(int i=1;i<=Q;++i)
if(zt[i+i-1]&zt[i+i])ans[++top]=i;
printf("%d\n",top);
for(int i=1;i<=top;++i)printf("%d\n",ans[i]);
return 0;
}

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

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

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

  2. BZOJ2437 NOI2011兔兔与蛋蛋(二分图匹配+博弈)

    首先将棋盘黑白染色,不妨令空格处为黑色.那么移动奇数次后空格一定处于白色格子,偶数次后空格一定处于黑色格子.所以若有某个格子的棋子颜色与棋盘颜色不同,这个棋子就是没有用的.并且空格与某棋子交换后,棋子 ...

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

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

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

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

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

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

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

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

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

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

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

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

  9. NOI2011 兔兔与蛋蛋游戏

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

随机推荐

  1. vbox虚拟机扩容(CentOS 7.2)

    Preface   My virtual machine was simply created by vagrant in default mode without anything about th ...

  2. 使用phpMyAdmin管理网站数据库(创建、导入、导出…)

    作为一名站长,最重视的就是网站的数据安全了.本节襄阳网站优化就来讲讲如何使用phpMyAdmin管理软件进行mysql数据库的管理,实现基本的数据库管理用户.数据库的创建.数据的导入和导出操作(网站备 ...

  3. SQL行列乾坤大挪移

    “生活总是这样,有时候,你需要一个苹果,但别人却给了你一个梨.” 今天dalao邮件里需要添加一张每月累计长长的图,可是,拿到手上的SQL导出数据不符合我最爱的pyecharts的数据输入格式,头大. ...

  4. Python登录,输入三次密码

    第一段python代码,写了一天,总算不报错了,值得纪念. 基本要求: 写一个登录界面,登录三次锁定用户 1. 包含一个用户信息文件,用户名和密码 2.黑名单文件 过程: 1.先检查是否在黑名单中,如 ...

  5. leetcode26_C++删除排序数组中的重复项

    给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度. 不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成. 示例 1 ...

  6. POJ 1417 并查集 dp

    After having drifted about in a small boat for a couple of days, Akira Crusoe Maeda was finally cast ...

  7. linux下搭建python机器学习环境

    前言 在 linux 下搭建 python 机器学习环境还是比较容易的,考虑到包依赖的问题,最好建立一个虚拟环境作为机器学习工作环境,在建立的虚拟环境中,再安装各种需要的包,主要有以下6个(这是看这个 ...

  8. 请教Amazon FBA里面Label Service, Stickerless, Commingled Inventory是什么意思?

    Accept Label Service接受标签服务,选择了以后下面的操作中会有一个让您打印标签的流程,您就可以按照FBA流程提示进行每一步标签服务的操作. Accept Stickless, Com ...

  9. 实现属于自己的TensorFlow(二) - 梯度计算与反向传播

    前言 上一篇中介绍了计算图以及前向传播的实现,本文中将主要介绍对于模型优化非常重要的反向传播算法以及反向传播算法中梯度计算的实现.因为在计算梯度的时候需要涉及到矩阵梯度的计算,本文针对几种常用操作的梯 ...

  10. 随机生成30道四则运算-NEW

    补充:紧跟上一个随机生成30道四则运算的题目,做了一点补充,可以有真分数之间的运算,于是需要在原来的基础上做一些改进. 首先指出上一个程序中的几个不足:1.每次执行的结果都一样,所以不能每天给孩子出3 ...