【BZOJ2437】【NOI2011】兔兔与蛋蛋(博弈论,二分图匹配)
【BZOJ2437】【NOI2011】兔兔与蛋蛋(博弈论,二分图匹配)
题面
题解
考虑一下暴力吧。
对于每个状态,无非就是要考虑它是否是必胜状态
这个直接用\(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】兔兔与蛋蛋(博弈论,二分图匹配)的更多相关文章
- BZOJ2437 [Noi2011]兔兔与蛋蛋 【博弈论 + 二分图匹配】
题目链接 BZOJ2437 题解 和JSOI2014很像 只不过这题动态删点 如果我们把空位置看做\(X\)的话,就会发现我们走的路径是一个\(OX\)交错的路径 然后将图二分染色,当前点必胜,当且仅 ...
- BZOJ2437 NOI2011兔兔与蛋蛋(二分图匹配+博弈)
首先将棋盘黑白染色,不妨令空格处为黑色.那么移动奇数次后空格一定处于白色格子,偶数次后空格一定处于黑色格子.所以若有某个格子的棋子颜色与棋盘颜色不同,这个棋子就是没有用的.并且空格与某棋子交换后,棋子 ...
- BZOJ1443 [JSOI2009]游戏Game 【博弈论 + 二分图匹配】
题目链接 BZOJ1443 题解 既然是网格图,便可以二分染色 二分染色后发现,游戏路径是黑白交错的 让人想到匹配时的增广路 后手要赢[指移动的后手],必须在一个与起点同色的地方终止 容易想到完全匹配 ...
- 【bzoj2437】[Noi2011]兔兔与蛋蛋 二分图最大匹配+博弈论
Description Input 输入的第一行包含两个正整数 n.m. 接下来 n行描述初始棋盘.其中第i 行包含 m个字符,每个字符都是大写英文字母"X".大写英文字母&quo ...
- 【BZOJ 2437】 2437: [Noi2011]兔兔与蛋蛋 (博弈+二分图匹配**)
未经博主同意不得转载 2437: [Noi2011]兔兔与蛋蛋 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 693 Solved: 442 Des ...
- bzoj 2437[Noi2011]兔兔与蛋蛋 黑白染色二分图+博弈+匈牙利新姿势
noi2011 兔兔与蛋蛋 题目大意 直接看原题吧 就是\(n*m\)的格子上有一些白棋和一些黑棋和唯一一个空格 兔兔先手,蛋蛋后手 兔兔要把与空格相邻的其中一个白棋移到空格里 蛋蛋要把与空格相邻的其 ...
- 博弈论(二分图匹配):NOI 2011 兔兔与蛋蛋游戏
Description Input 输入的第一行包含两个正整数 n.m. 接下来 n行描述初始棋盘.其中第i 行包含 m个字符,每个字符都是大写英文字母"X".大写英文字母&quo ...
- 2437: [Noi2011]兔兔与蛋蛋 - BZOJ
Description Input 输入的第一行包含两个正整数 n.m.接下来 n行描述初始棋盘.其中第i 行包含 m个字符,每个字符都是大写英文字母"X".大写英文字母" ...
- NOI2011 兔兔与蛋蛋游戏
http://www.lydsy.com/JudgeOnline/problem.php?id=2437 这道题真是极好的. 75分做法: 搜索. 出题人真的挺良心的,前15个数据点的范围都很小,可以 ...
随机推荐
- springboot入门之一:环境搭建(续)
在上篇博客中从springboot的入门到运行一个springboot项目进行了简单讲述,详情请查看“springboot入门之一”.下面继续对springboot做讲述. 开发springboot测 ...
- Django之视图系统
Django的View(视图) 一个视图函数(类),简称视图,是一个简单的python函数(类),它接受web请求并返回web响应. 响应可以是一张网页的HTML内容,一个重定向,一个404错误,或者 ...
- List Leaves 树的层序遍历
3-树2 List Leaves (25 分) Given a tree, you are supposed to list all the leaves in the order of top do ...
- Node2vec 代码分析
Node2vec 代码从Github上clone到本地,主要是main.py和node2vec.py两个文件. 下面把我的读代码注释放到上面来, import numpy as np import n ...
- 在香港网站使用工商银行的MasterCard,工商银行所犯的低级的错误,金融安全何在
- ES6的新特性(6)——正则的扩展
正则的扩展 RegExp 构造函数 在 ES5 中,RegExp构造函数的参数有两种情况. 第一种情况是,参数是字符串,这时第二个参数表示正则表达式的修饰符(flag). var regex = ne ...
- js 插件 issue
1 iscroll 5 和 lazyload 同时使用 转自 yinjie //lazyload var $scrollEle = $("#wrapper") $("i ...
- 树状数组怒刷sum!!!(前缀和应用)
我们知道我们利用树状数组维护的是存到其中的a[ ]数组,但是我们做题需要的是sum[ ]数组,这才是我们真正需要的有用的信息,写这篇博客的目的便是整理一下sum数组是怎么样来应用解题的. 1. Sta ...
- 第五次作业psp
psp 进度条 代码累积折线图 博文累积折线图 psp饼状图 团体合作体会:经过这几天的团队,我感受良多.发现团队协作是一件非常让人兴奋的事情.团队成员们互相帮助,互相协作,让我感受最深的就是当自己为 ...
- MathExamV2.0四则混合运算计算题生成器
MathExamV2.0四则混合运算计算题生成器----211606360 丁培晖 211606343 杨宇潇 一.预估与实际 PSP2.1 Personal Software Process Sta ...