暑假做这道题时,纠结了N久=。=......最后跑到5机房来问秋哥和奥特曼,结果.......就陪着他们在看魁拔(>.<)......
反正就是没有写啦。亡羊补牢,也算是对二分图匹配的复习吧。
操作可以转化为路径问题,进行黑白染色之后,变成二分图。
这道题的关键之处在于,先手必胜点是必定出现在最大匹配中的点。
这个不难理解,一旦出现在最大匹配中,先手必定能沿着匹配边走,而后手只能沿着非匹配边走,最终无路可走。
而如果兔兔操作时处于先手必胜点,操作后的点仍然是先手必胜点,它就必定犯了错。
为了图思维方便,直接写了k次匈牙利,慢是慢了点,但是没有什么纠结的地方。
# include <cstdlib>
# include <cstdio>
# include <cstring>
using namespace std;
const int maxn=40+5;
int ans[1000+5],id[maxn][maxn], lk[maxn*maxn][maxn*maxn],point[maxn*maxn];
bool v[maxn*maxn], can[maxn*maxn];
int n,m,sx,sy,mx[4],my[4];
inline int abs(int x){return x<0?-x:x;};
void link(int x, int y){lk[x][++lk[x][0]]=y;}
void prepare()
{
int i,j,k,ti,tj;
for (i = 1; i <= n; i++)
for (j = 1; j <= m; j++)
if (abs(i-sx+j-sy) & 1) can[(i-1)*m+j]=(1==id[i][j]);
else can[(i-1)*m+j] = (-1==id[i][j]);
for (i = 1; i <= n; i++)
for (j = 1; j <= m; j++)
if (can[(i-1)*m+j] && id[i][j]==-1)
for (k = 0; k < 4; k++)
{
ti=i+mx[k], tj= j+my[k];
if (can[(ti-1)*m+tj] && id[ti][tj]==1)
link((i-1)*m+j, (ti-1)*m+tj);
}
}
bool dfs(int x)
{
int i,ne; v[x]=true;
for (i = 1; i <= lk[x][0]; i++)
{
ne=lk[x][i];
if ((!v[ne])&&can[ne])
{
v[ne]=true;
if (point[ne]==0||dfs(point[ne]))
{point[ne]= x; return true;}
}
}
return false;
}
bool check(int x, int y)
{
int i,j,sum=0;
memset(point,0,sizeof(point));
for (i = 1;i <= n; i++)
for (j = 1; j <= m; j++)
if (can[(i-1)*m+j] && id[i][j]==-1)
{
memset(v,false,sizeof(v));
if (dfs((i-1)*m+j)) sum++;
}
memset(point,0,sizeof(point));
can[(x-1)*m+y]=false;
for (i = 1;i <= n; i++)
for (j = 1; j <= m; j++)
if (can[(i-1)*m+j] && id[i][j]==-1)
{
memset(v,false,sizeof(v));
if (dfs((i-1)*m+j)) sum--;
}
if (sum) return true; else return false;
}
int main()
{
int test,i,j,x,y; char c;
//freopen("game.in", "r", stdin);
//freopen("game.out", "w", stdout);
scanf("%d%d\n", &n, &m);
mx[0]=1;mx[1]=0;mx[2]=-1;mx[3]=0;
my[0]=0;my[1]=1;my[2]=0;my[3]=-1;
for (i = 1; i <=n; i++)
{
for (j =1; j <=m; j++)
{
scanf("%c", &c);
if (c=='O') id[i][j] = 1;
else if (c=='X') id[i][j] = -1;
else sx=i,sy=j, id[i][j]=-1;
}
scanf("\n");
}
prepare();
scanf("%d", &test);
for (i = 1; i <= test; i++)
{
scanf("%d%d", &x, &y);
bool win=check(sx,sy); can[(sx-1)*m+sy]=false;
sx=x,sy=y;
scanf("%d%d", &x, &y);
if (win && check(sx,sy)) ans[++ans[0]]=i; can[(sx-1)*m+sy]=false;
sx=x,sy=y;
}
printf("%d\n", ans[0]);
for (i = 1; i <= ans[0]; i++)
printf("%d\n", ans[i]);
return 0;
}