题意
n,m<=40,k<=1000
分析
如果相邻格子之间有边,那么这就是一个二分图。不妨把起点也看成黑色,那么显然每个点每条边只能被走一次,这就变成了一个二分图博弈问题。
当起点必然是最大匹配中的边则先手必胜。因为先手可以一直沿着匹配边走,如果后手走到了某个不匹配点,则与起点必然是匹配点不符,故先手必胜。
若起点可能不是最大匹配中的边,则后手必胜。因为无论先手怎么走都会走到一个匹配点,后手可以沿着匹配边走。若先手走到某个非匹配点,则出现增广路,与最大匹配不符,故后手必胜。
那么问题就转变成了要求某个点是否一定是最大匹配中的点,且要支持删点。
那么我们可以暴力的先把该点删掉,再看看其对应匹配点是否能找到增广路即可。
复杂度O(nmk)。
代码
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=45;
int n,m,cnt,last[N*N],dx[4]={0,1,0,-1},dy[4]={1,0,-1,0},match[N*N];
bool col[N][N],odd[N][N],ans[2005],del[N*N],vis[N*N];
struct edge{int to,next;}e[N*N*2];
char str[N];
int read()
{
int x=0,f=1;char ch=getchar();
while (ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int point(int x,int y)
{
return (x-1)*m+y;
}
void addedge(int u,int v)
{
e[++cnt].to=v;e[cnt].next=last[u];last[u]=cnt;
}
bool find(int x)
{
for (int i=last[x];i;i=e[i].next)
{
if (vis[e[i].to]||del[e[i].to]) continue;
vis[e[i].to]=1;
if (!match[e[i].to]||find(match[e[i].to]))
{
match[e[i].to]=x;
match[x]=e[i].to;
return 1;
}
}
return 0;
}
bool check(int x)
{
if (!match[x]) return 0;
memset(vis,0,sizeof(vis));
del[x]=1;int y=match[x];
match[x]=match[y]=0;
if (find(y)) {del[x]=0;return 0;}
else {del[x]=0;match[x]=y;match[y]=x;return 1;}
}
int main()
{
n=read();m=read();int sx,sy;
for (int i=1;i<=n;i++)
{
scanf("%s",str+1);
for (int j=1;j<=m;j++)
{
if (i%2==j%2) odd[i][j]=1;
if (str[j]=='X') col[i][j]=1;
else if (str[j]=='O') col[i][j]=0;
else sx=i,sy=j,col[i][j]=1;
}
}
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
{
if (odd[i][j]^col[i][j]!=odd[sx][sy]^col[sx][sy]) {del[point(i,j)]=1;continue;}
for (int k=0;k<4;k++)
{
int p=i+dx[k],q=j+dy[k];
if (p<1||p>n||q<1||q>m) continue;
if (odd[p][q]^col[p][q]==odd[sx][sy]^col[sx][sy]&&col[i][j]!=col[p][q]) addedge(point(i,j),point(p,q));
}
}
int now=point(sx,sy);
for (int i=1;i<=n*m;i++)
{
if (del[i]||match[i]) continue;
memset(vis,0,sizeof(vis));
find(i);
}
ans[0]=check(now);
int r=read();
for (int i=1;i<=r*2;i++)
{
del[now]=1;int x=match[now];
if (x) {memset(vis,0,sizeof(vis));match[x]=0;find(x);}
int p=read(),q=read();
now=point(p,q);
ans[i]=check(now);
}
int tot=0;
for (int i=1;i<=r*2;i+=2) if (ans[i]&&ans[i-1]) tot++;
printf("%d\n",tot);
for (int i=1;i<=r*2;i+=2) if (ans[i]&&ans[i-1]) printf("%d\n",i/2+1);
return 0;
}