暑假做这道题时,纠结了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; }