2437: [Noi2011]兔兔与蛋蛋 - BZOJ

Description

2437: [Noi2011]兔兔与蛋蛋 - BZOJ_第1张图片


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

2437: [Noi2011]兔兔与蛋蛋 - BZOJ_第2张图片

 

 

神题,竟然是二分图匹配,看了题解才知道

因为走的路线黑白交替所以我们考虑二分图匹配,相邻的黑白连边(空格一开始视为黑色)

然后可以发现走的路线是一条交错轨,那么必胜的条件是起点一定在最大匹配中

如果在的话,那么我们每次都走匹配边,最后没有路的一定是后手(可以画图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.
View Code

 

你可能感兴趣的:(ZOJ)