2437: [Noi2011]兔兔与蛋蛋 - BZOJ
Description
Input
输入的第一行包含两个正整数 n、m。
接下来 n行描述初始棋盘。其中第i 行包含 m个字符,每个字符都是大写英文字母"X"、大写英文字母"O"或点号"."之一,分别表示对应的棋盘格中有黑色棋子、有白色棋子和没有棋子。其中点号"."恰好出现一次。
接下来一行包含一个整数 k(1≤k≤1000) ,表示兔兔和蛋蛋各进行了k次操作。
接下来 2k行描述一局游戏的过程。其中第 2i – 1行是兔兔的第 i 次操作(编号为i的操作) ,第2i行是蛋蛋的第i次操作。每个操作使用两个整数x,y来描述,表示将第x行第y列中的棋子移进空格中。
输入保证整个棋盘中只有一个格子没有棋子, 游戏过程中兔兔和蛋蛋的每个操作都是合法的,且最后蛋蛋获胜。
Output
输出文件的第一行包含一个整数r,表示兔兔犯错误的总次数。
接下来r 行按递增的顺序给出兔兔“犯错误”的操作编号。其中第 i 行包含一个整数ai表示兔兔第i 个犯错误的操作是他在游戏中的第 ai次操作。
1 ≤n≤ 40, 1 ≤m≤ 40
Sample Input
样例一:
1 6
XO.OXO
1
1 2
1 1
样例二:
3 3
XOX
O.O
XOX
4
2 3
1 3
1 2
1 1
2 1
3 1
3 2
3 3
样例三:
4 4
OOXX
OXXO
OO.O
XXXO
2
3 2
2 2
1 2
1 3
Sample Output
样例一:
1
1
样例二:
0
样例三:
2
1
2
样例1对应图一中的游戏过程
样例2对应图三中的游戏过程
HINT
神题,竟然是二分图匹配,看了题解才知道
因为走的路线黑白交替所以我们考虑二分图匹配,相邻的黑白连边(空格一开始视为黑色)
然后可以发现走的路线是一条交错轨,那么必胜的条件是起点一定在最大匹配中
如果在的话,那么我们每次都走匹配边,最后没有路的一定是后手(可以画图yy一下,交错轨走到最后一定是一条匹配边,要不然起点就不一定在最大匹配中了)
如果起点不一定在最大匹配中那么,起点连的点都一定在最大匹配中(在去掉起点之后)(可以用反证法)
1 const 2 maxn=42; 3 maxk=1010; 4 var 5 p,a:array[0..maxn,0..maxn]of longint; 6 first,last,next:array[0..maxn*maxn*20]of longint; 7 link:array[0..maxn*maxn]of longint; 8 vis:array[0..maxn*maxn]of boolean; 9 ans:array[0..maxk]of longint; 10 n,m,k,tot,cnt,xi,yi:longint; 11 12 procedure insert(x,y:longint); 13 begin 14 inc(tot);last[tot]:=y;next[tot]:=first[x];first[x]:=tot; 15 inc(tot);last[tot]:=x;next[tot]:=first[y];first[y]:=tot; 16 end; 17 18 function find(x:longint):boolean; 19 var 20 i:longint; 21 begin 22 if x<0 then exit(false); 23 i:=first[x]; 24 while i<>0 do 25 begin 26 if not vis[last[i]] then 27 begin 28 vis[last[i]]:=true; 29 if (link[last[i]]=0) or (find(link[last[i]])) then 30 begin 31 link[x]:=last[i]; 32 link[last[i]]:=x; 33 exit(true); 34 end; 35 end; 36 i:=next[i]; 37 end; 38 exit(false); 39 end; 40 41 procedure main; 42 var 43 i,j,v:longint; 44 c:char; 45 flag1,flag2:boolean; 46 begin 47 read(n,m); 48 for i:=1 to n do 49 for j:=1 to m do 50 begin 51 inc(cnt);p[i,j]:=cnt; 52 repeat 53 read(c); 54 until (c='X') or (c='O') or (c='.'); 55 if c='.' then 56 begin 57 xi:=i; 58 yi:=j; 59 end; 60 if c<>'O' then a[i,j]:=1; 61 if (i>1) and (a[i,j]<>a[i-1,j]) then insert(p[i,j],p[i-1,j]); 62 if (j>1) and (a[i,j]<>a[i,j-1]) then insert(p[i,j],p[i,j-1]); 63 end; 64 for i:=1 to n do 65 for j:=1 to m do 66 if a[i,j]=0 then 67 begin 68 fillchar(vis,sizeof(vis),false); 69 find(p[i,j]); 70 end; 71 read(k);cnt:=0; 72 for i:=1 to k do 73 begin 74 v:=link[p[xi,yi]];link[v]:=0; 75 link[p[xi,yi]]:=-1; 76 fillchar(vis,sizeof(vis),false); 77 if v=0 then flag1:=false 78 else flag1:=not find(v); 79 read(xi,yi); 80 v:=link[p[xi,yi]];link[v]:=0; 81 link[p[xi,yi]]:=-1; 82 fillchar(vis,sizeof(vis),false); 83 if v=0 then flag2:=false 84 else flag2:=not find(v); 85 read(xi,yi); 86 if flag1 and flag2 then 87 begin 88 inc(cnt);ans[cnt]:=i; 89 end; 90 end; 91 writeln(cnt); 92 for i:=1 to cnt do writeln(ans[i]); 93 end; 94 95 begin 96 main; 97 end.