Description
Analysis
这道题一开始就想岔了...
可以发现从一个节点出去的马,如果回到该节点的话,经过的节点数一定是偶数(包括自己)。
一开始我想的是既然都是偶数,那么可以用两次DFS分别统计,具体地说就是对一个联通块,先从一个节点DFS,求出答案1,然后再从上一次节点的相邻节点再做一次,求出答案2,去一个最大值。
然后WA3次,我现在还不知道为什么这样是错的。
之后又发现,因为都是偶数环,进行黑白染色不会产生矛盾,然后就是赤裸裸的二分图最大独立集问题了。
二分图最大独立集=顶点数-二分图最小顶点覆盖集=顶点数-二分图最大匹配。
听说匈牙利被卡,就写了SAP,但听说Dinic完艹SAP!?
const
dx:array[1..8] of longint=(-1,-2,1,2,-1,-2,1,2);
dy:array[1..8] of longint=(-2,-1,-2,-1,2,1,2,1);
var
edge,n,i,j,k,x,y,ans,all,vs,vt,num:longint;
e:array[1..1000000,1..3] of longint;
fr,d,vd:array[0..40000] of longint;
a:array[1..200,1..200] of char;
procedure add(x,y,c:longint);
begin
inc(edge); e[edge,1]:=y; e[edge,2]:=fr[x]; e[edge,3]:=c; fr[x]:=edge;
end;
function get(x,y:longint):longint;
begin
exit((x-1)*n+y);
end;
function min(a,b:longint):longint;
begin
if a<b then exit(a) else exit(b);
end;
function dfs(u,flow:longint):longint;
var
k,tmp:longint;
begin
if u=vt then exit(flow);
dfs:=0;
k:=fr[u];
while k<>0 do begin
if (e[k,3]>0) and (d[u]=d[e[k,1]]+1) then begin
tmp:=dfs(e[k,1],min(e[k,3],flow-dfs));
inc(dfs,tmp);
dec(e[k,3],tmp);
if odd(k) then inc(e[k+1,3],tmp) else inc(e[k-1,3],tmp);
if dfs=flow then exit;
end;
k:=e[k,2];
end;
dec(vd[d[u]]);
if vd[d[u]]=0 then d[vs]:=num;
inc(d[u]);
inc(vd[d[u]]);
end;
begin
readln(n);
for i:=1 to n do begin
for j:=1 to n do
read(a[i,j]);
readln;
end;
vs:=0; vt:=n*n+1; num:=vt+1; vd[0]:=num;
for i:=1 to n do begin
for j:=1 to n do begin
if a[i,j]='1' then continue;
inc(all);
if (i+j) and 1=0 then begin
add(vs,get(i,j),1);
add(get(i,j),vs,0);
for k:=1 to 8 do begin
x:=i+dx[k]; y:=j+dy[k];
if (x<1) or (y<1) or (x>n) or (y>n) then continue;
if a[x,y]='1' then continue;
add(get(i,j),get(x,y),1);
add(get(x,y),get(i,j),0);
end;
end
else begin
add(get(i,j),vt,1);
add(vt,get(i,j),0);
end;
end;
end;
while d[vs]<num do ans:=ans+dfs(vs,maxlongint);
writeln(all-ans);
end.