您的位置:首页 > 其它

bzoj2437 [Noi2011]兔兔与蛋蛋

2018-01-25 20:06 387 查看
二分图博弈果然都是一个套路,必经点必胜,非必经点必败,

但是肯定不能没走一步就重新建图判断必胜还是必败,那么我们可以这样:每走一步就把这个点删掉,然后find他原来的匹配,如果找不到,就说明他是必经点,否则就是非必经点。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>
#define N 1601
using namespace std;
int e=1,head
;
struct edge{int v,next;}ed[N*4];
void add(int u,int v){ed[e].v=v;ed[e].next=head[u];head[u]=e++;}
int pp
,del
,id[41][41];
bool vis
,ans
;
bool find(int x){
for(int i=head[x];i;i=ed[i].next){
int v=ed[i].v;
if(del[v]||vis[v])continue;vis[v]=1;
if(!pp[v]||find(pp[v])){
pp[v]=x;pp[x]=v;
return 1;
}
}return 0;
}
int a[41][41],be,n,m,T,sx,sy,tot1,tot2,tot;
char ch[41];
bool check(int i,int j){return ((i+j)&1)^a[i][j]==be;}
int f
,f_cnt;
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%s",ch+1);
for(int j=1;j<=m;j++)
if(ch[j]=='O')a[i][j]=1;
else if(ch[j]=='X')a[i][j]=0;
else sx=i,sy=j;
}
be=(sx+sy)&1;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)if(check(i,j))
if(a[i][j])id[i][j]=++tot1;
else id[i][j]=++tot2;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)if(check(i,j)&&(!a[i][j]))
id[i][j]+=tot1;
tot=tot1+tot2;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)if(id[i][j]){
if(id[i+1][j])add(id[i][j],id[i+1][j]);
if(id[i][j+1])add(id[i][j],id[i][j+1]);
if(id[i-1][j])add(id[i][j],id[i-1][j]);
if(id[i][j-1])add(id[i][j],id[i][j-1]);
}
for(int i=1;i<=tot1;i++){
memset(vis,0,sizeof vis);
find(i);
}
scanf("%d",&T);T<<=1;
for(int i=1,x,y;i<=T;i++){
int now=id[sx][sy],p=pp[now];
del[now]=1;pp[now]=pp[p]=0;
if(!p)ans[i]=0;
else{
memset(vis,0,sizeof vis);
ans[i]=find(p)^1;
}
scanf("%d%d",&sx,&sy);
}
for(int i=1;i<=T;i+=2)
if(ans[i]&&ans[i+1])f[++f_cnt]=(i+1)>>1;
printf("%d\n",f_cnt);
for(int i=1;i<=f_cnt;i++)
printf("%d\n",f[i]);
return 0;
}


View Code
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: