bzoj2437

时间:2023-03-10 01:02:46
bzoj2437

会做jsoi那道game,这题就非常简单了吧

我们考虑空格的移动,显然,初始与空格位置距离为奇数的黑棋和距离为偶数的白棋并没有什么用,

空格不会移到那,我们直接把他们当作障碍,其他点我们当作可移动区域

这不就和game那道题一样了吗,只不过这题不问棋子放哪

而是给定棋子位置,问当前是否是先手必胜

(错误操作就是指当前是先手必胜而移动一格还是先手必胜的操作)

我们对图重新黑白染色,做二分图匹配,显然,棋子在一定能被匹配的点上时,是先手必胜

证明类似game,因为棋子在一定在一定能被匹配的点上,我们第一步走向匹配点

下一步对方要么不能走,要么走一条非匹配边,那所到达的点,一定是匹配了的

否则,一开始的点就不一定在匹配,与假设矛盾,所以最后走的一条边一定是匹配边得证

至于怎么找一定能被匹配的点,我们做完二分图匹配后,如果这个点匹配了,那么我们删掉这个点,从这个点配对的点出发看是否能找到增广路即可

 const dx:array[..] of longint=(,,,-);
dy:array[..] of longint=(,-,,); type node=record
po,next:longint;
end; var e:array[..] of node;
v:array[..] of boolean;
b:array[..,..] of longint;
a:array[..,..] of char;
mat,p,c:array[..] of longint;
t,xx,yy,i,n,m,j,k,len,x,y,ans:longint;
f1,f2:boolean; procedure add(x,y:longint);
begin
inc(len);
e[len].po:=y;
e[len].next:=p[x];
p[x]:=len;
end; function dfs(x:longint):boolean;
var i,y:longint;
begin
v[x]:=true;
i:=p[x];
while i<> do
begin
y:=e[i].po;
if not v[y] and (mat[y]<>-) then
begin
v[y]:=true;
if (mat[y]=) or dfs(mat[y]) then
begin
mat[y]:=x;
mat[x]:=y;
exit(true);
end;
end;
i:=e[i].next;
end;
exit(false);
end; function check:boolean;
var j,k:longint;
begin
k:=b[x,y];
j:=mat[k];
mat[j]:=;
mat[k]:=-;
if j= then exit(false)
else begin
fillchar(v,sizeof(v),false);
exit(not dfs(j));
end;
end; begin
readln(n,m);
for i:= to n do
begin
for j:= to m do
begin
read(a[i,j]);
if a[i,j]='.' then
begin
x:=i;
y:=j;
a[i,j]:='X';
end;
end;
readln;
end;
for i:= to n do
for j:= to m do
if (a[i,j]='O') xor ((abs(i-x)+abs(j-y)) mod =) then
begin
inc(t);
b[i,j]:=t;
end; for i:= to n do
for j:= to m do
if b[i,j]> then
begin
for k:= to do
begin
xx:=i+dx[k];
yy:=j+dy[k];
if b[xx,yy]> then add(b[i,j],b[xx,yy]);
end;
end; for i:= to t do
if mat[i]= then
begin
fillchar(v,sizeof(v),false);
dfs(i);
end; readln(k);
for i:= to k do
begin
f1:=check;
readln(x,y);
f2:=check;
if f1 and f2 then
begin
inc(ans);
c[ans]:=i;
end;
readln(x,y);
end;
writeln(ans);
for i:= to ans do
writeln(c[i]);
end.