传送门1
传送门2
思路:
关于证明
算是bzoj1443的强化版吧
但我是先写的这道题再写的bzoj1443,所以刚开始比较懵逼
二分图中的点是空格、与空格坐标和的奇偶相同的黑点、坐标和奇偶不同的白点
还有一点要注意的是每次删点后是不用再还原回去的,因为被移动的黑点(白点)已经符合二分图中点的条件了
如果蛋蛋走前时先手必胜且上一次兔兔走前时先手必胜,答案加1(s)
代码:
#include<cstdio>
#include<cstring>
using namespace std;
int n,m,k,s,t,cnt,tot;
int a[43][43],first[1605],id[43][43],belong[1605],ans[1005];
int dx[4]={0,0,-1,1},dy[4]={1,-1,0,0};
bool vis[1605],del[1605],ok[1005];
struct edge{
int v,next;
}e[10000];
int in()
{
char c=getchar();
while (c!='O'&&c!='X'&&c!='.') c=getchar();
if (c=='O') return 1;
if (c=='X') return -1;
return 0;
}
void add(int u,int v){e[++tot]=(edge){v,first[u]};first[u]=tot;}
int find(int x)
{
if (del[x]) return 0;
for (int i=first[x];i;i=e[i].next)
if (!vis[e[i].v]&&!del[e[i].v])
{
vis[e[i].v]=1;
if (!belong[e[i].v]||find(belong[e[i].v]))
{
belong[e[i].v]=x,
belong[x]=e[i].v;
return 1;
}
}
return 0;
}
main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=n;++i)
for (int j=1;j<=m;++j)
{
a[i][j]=in();
if (!a[i][j]) s=i,t=j;
}
for (int i=1;i<=n;++i)
for (int j=1;j<=m;++j)
if (((i+j&1)!=(s+t&1)&&a[i][j]>0)||((i+j&1)==(s+t&1)&&a[i][j]<=0))
id[i][j]=++cnt;
for (int i=1;i<=n;++i)
for (int j=1;j<=m;++j)
if (id[i][j])
{
for (int k=0;k<4;++k)
if (id[i+dx[k]][j+dy[k]])
add(id[i][j],id[i+dx[k]][j+dy[k]]);
}
for (int i=1;i<=cnt;++i)
if (!belong[i])
memset(vis,0,sizeof(vis)),
find(i);
scanf("%d",&k);
int nx,ny;
for (int i=1;i<=k<<1;++i)
{
del[id[s][t]]=1;
if (belong[id[s][t]])
{
belong[belong[id[s][t]]]=0;
memset(vis,0,sizeof(vis));
ok[i]=!find(belong[id[s][t]]);
if (!(i&1)&&ok[i]&&ok[i-1])
ans[++ans[0]]=i>>1;
}
scanf("%d%d",&s,&t);
}
printf("%d\n",ans[0]);
for (int i=1;i<=ans[0];++i) printf("%d\n",ans[i]);
}