暑假做這道題時,糾結了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;
}