结论 不会有同一个棋子移动两次
反证法,对于第一个移动第二次的棋子
设两次移动之间(含)的移动的棋子为 A 1 , A 2 , A 3 , … … , A n A_1,A_2,A_3,……,A_n A1,A2,A3,……,An(指棋子本身而非位置)
因为最后移回来了,所以往上和往下、往左和往右次数相同
所以 n n n是偶数 然后 A 1 A_1 A1和 A n A_n An颜色不同
但这个棋子开始被移到当前位置,最后被移走,所以 A 1 = A n A_1=A_n A1=An,矛盾
所以移动路径没有交
既然这样,我们就不用考虑棋盘具体的变化,而看成空格交替走两个颜色
然后和上一道题就一样了
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cctype>
#define MAXN 2005
#define MAXM 10005
using namespace std;
struct edge{int u,v;}e[MAXM];
int head[MAXN],nxt[MAXM],cnt;
void addnode(int u,int v)
{
e[++cnt]=(edge){u,v};
nxt[cnt]=head[u];
head[u]=cnt;
}
int n,m;
#define id(x,y) (((x)-1)*m+(y))
char s[50][50];
const int dx[]={-1,1,0,0},dy[]={0,0,-1,1};
bool del[MAXN];
int link[MAXN],used[MAXN];
bool find(int u)
{
for (int i=head[u];i;i=nxt[i])
if (!used[e[i].v]&&!del[e[i].v])
{
used[e[i].v]=1;
if (!del[link[e[i].v]]&&(!link[e[i].v]||find(link[e[i].v])))
{
link[u]=e[i].v,link[e[i].v]=u;
return true;
}
}
return false;
}
int calc()
{
memset(link,0,sizeof(link));
int ans=0;
for (int x=1;x<=n;x++)
for (int y=1;y<=m;y++)
if (s[x][y]!='O'&&!del[id(x,y)])
memset(used,0,sizeof(used)),ans+=find(id(x,y));
return ans;
}
bool win[MAXN];
int main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++) scanf("%s",s[i]+1);
int st;
for (int x=1;x<=n;x++)
for (int y=1;y<=m;y++)
if (s[x][y]!='O')
{
for (int i=0;i<4;i++)
if (s[x+dx[i]][y+dy[i]]=='O')
addnode(id(x,y),id(x+dx[i],y+dy[i]));
if (s[x][y]=='.') st=id(x,y);
}
int k,tot=0;
scanf("%d",&k);
int mmat=calc();
for (int i=1;i<=2*k;i++)
{
del[st]=1;
int t=calc();
if (mmat!=t) win[i]=1;
mmat=t;
int x,y;
scanf("%d%d",&x,&y);
st=id(x,y);
}
for (int i=1;i<=k;i++) if (win[2*i-1]&&win[2*i]) ++tot;
printf("%d\n",tot);
for (int i=1;i<=k;i++) if (win[2*i-1]&&win[2*i]) printf("%d\n",i);
return 0;
}