【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. springboot入门之一:环境搭建(续)

    在上篇博客中从springboot的入门到运行一个springboot项目进行了简单讲述,详情请查看“springboot入门之一”.下面继续对springboot做讲述. 开发springboot测 ...

  2. Django之视图系统

    Django的View(视图) 一个视图函数(类),简称视图,是一个简单的python函数(类),它接受web请求并返回web响应. 响应可以是一张网页的HTML内容,一个重定向,一个404错误,或者 ...

  3. List Leaves 树的层序遍历

    3-树2 List Leaves (25 分) Given a tree, you are supposed to list all the leaves in the order of top do ...

  4. Node2vec 代码分析

    Node2vec 代码从Github上clone到本地,主要是main.py和node2vec.py两个文件. 下面把我的读代码注释放到上面来, import numpy as np import n ...

  5. 在香港网站使用工商银行的MasterCard,工商银行所犯的低级的错误,金融安全何在

  6. ES6的新特性(6)——正则的扩展

    正则的扩展 RegExp 构造函数 在 ES5 中,RegExp构造函数的参数有两种情况. 第一种情况是,参数是字符串,这时第二个参数表示正则表达式的修饰符(flag). var regex = ne ...

  7. js 插件 issue

    1 iscroll 5 和 lazyload 同时使用  转自 yinjie //lazyload var $scrollEle = $("#wrapper") $("i ...

  8. 树状数组怒刷sum!!!(前缀和应用)

    我们知道我们利用树状数组维护的是存到其中的a[ ]数组,但是我们做题需要的是sum[ ]数组,这才是我们真正需要的有用的信息,写这篇博客的目的便是整理一下sum数组是怎么样来应用解题的. 1. Sta ...

  9. 第五次作业psp

    psp 进度条 代码累积折线图 博文累积折线图 psp饼状图 团体合作体会:经过这几天的团队,我感受良多.发现团队协作是一件非常让人兴奋的事情.团队成员们互相帮助,互相协作,让我感受最深的就是当自己为 ...

  10. MathExamV2.0四则混合运算计算题生成器

    MathExamV2.0四则混合运算计算题生成器----211606360 丁培晖 211606343 杨宇潇 一.预估与实际 PSP2.1 Personal Software Process Sta ...