您的位置:首页 > 其它

bzoj2437 [Noi2011]兔兔与蛋蛋

2016-09-08 14:55 330 查看
题解:我们将棋盘分成黑白格子(相邻格子颜色不同),将空格染成黑色,那么我们可以知道X为合法棋子当且仅当X在黑色格子,而O为合法棋子当且仅当O在白色格子。

相邻合法棋子(空格也为合法)连边,则我们得到无向图,而它也是二部图,当空格一定是在最大匹配中时,则先手必胜;否则先手必败。若不一定在,则空格可能在偶数条交错路,或者有点可以代替空格(此时空格可不在最大匹配中),那么此时后手总有办法走到先手所在的部,即先手无法移动。

判断空格是否在最大匹配中,若空格没有对应的匹配点,那么空格肯定不在最大匹配中;若有匹配点,则把空格标记掉,同时将空格和对应匹配点的信息标为空,搜索匹配点看能否增大匹配数,若能则不一定在最大匹配中。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <vector>

using namespace std;

const int N=45;
char str

;
int num

,cnt,tot;
int del[N*N],vis[N*N],match[N*N],res[N*N];
int Ans[2000];
int xx,yy;
int n,m;
vector<int>V[N*N];
bool dfs(int u){
for (int i=0;i<int(V[u].size());i++){
int v=V[u][i];
if (del[v] || vis[v]==tot)continue;
vis[v]=tot;
if (match[v]==0 || dfs(match[v])){
match[v]=u;match[u]=v;
return true;
}
}
return false;
}
void Add(int u,int v){
V[u].push_back(v);V[v].push_back(u);
}
int main()
{
//freopen("1.txt","r",stdin);
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++){
scanf("%s",str[i]+1);
for (int j=1;j<=m;j++)if (str[i][j]=='.')
{xx=i;yy=j;}
}
str[xx][yy]='X';
memset(num,0,sizeof num);
cnt=0;
for (int i=1;i<=n;i++)for (int j=1;j<=m;j++){
if (str[i][j]=='X' && (abs(xx-i)+abs(yy-j))%2==0)
cnt++,num[i][j]=cnt;
if (str[i][j]=='O' && (abs(xx-i)+abs(yy-j))%2==1)
cnt++,num[i][j]=cnt;
}
for (int i=1;i<=cnt;i++)V[i].clear();
for (int i=1;i<=n;i++)for (int j=(i%2==0)?2:1;j<=m;j+=2){
if (j>1 && num[i][j-1])Add(num[i][j],num[i][j-1]);
if (j<m && num[i][j+1])Add(num[i][j],num[i][j+1]);
if (i>1 && num[i-1][j])Add(num[i][j],num[i-1][j]);
if (i<n && num[i+1][j])Add(num[i][j],num[i+1][j]);
}
memset(vis,0,sizeof vis);
memset(del,0,sizeof del);
memset(match,0,sizeof match);
tot=0;
for (int i=1;i<=n;i++)for (int j=(i%2==0)?2:1;j<=m;j+=2)/*if (num[i][j] && !match[num[i][j]])*/{//只能从二分图的一边搜,为什么不能加/**/里面的部分
tot++;dfs(num[i][j]);
}
int Q;scanf("%d",&Q);Q<<=1;
for (int i=1;i<=Q;i++){
if (match[num[xx][yy]]==0){
res[i]=0;//i走之前预判必败还是必胜,0表示必败
del[num[xx][yy]]=1;
}else{
int tmp;
match[tmp=match[num[xx][yy]]]=0;match[num[xx][yy]]=0;
del[num[xx][yy]]=1;
tot++;res[i]=!dfs(tmp);
}
scanf("%d%d",&xx,&yy);
}
int gs=0;
for (int i=1;i<=Q;i+=2)if (res[i] && res[i+1])gs++,Ans[gs]=(i+1)>>1;
printf("%d\n",gs);
for (int i=1;i<=gs;i++)printf("%d\n",Ans[i]);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  博弈 二分图匹配