由于只能向下走,这样路线就不可能达成一个环,而且又鉴于每个点只能到达一遍,每一次的代价只存在于重设出发点,于是很容易的就想到了最小路径覆盖,赤果果的网络流。把每个节点拆成两个,i入和i出。如果i可以到达j,那么就连一条i出到j入的边,再由源向每一个出连一条边,由入向汇连一条边。上述边的流量都为1。答案就是总的点数减最大流。当然这道题也可以用匈牙利算法做。
program p03; type bian=record next,point,f:longint; end; var b:array[0..5000000] of bian; p,dst,s:array[0..500000] of longint; pd:array[0..500000] of boolean; bo:array[1..600,1..600] of boolean; tot,len,i,j,n,m,r,c:longint; ch:char; procedure getchar(var ch:char); begin read(ch); while (ch<>'.') and (ch<>'x')do read(ch); end; function min(k1,k2:longint):longint; begin if k1<k2 then exit(k1) else exit(k2); end; function change(k1,k2:longint):longint; var i,j,k,num:longint; begin if (k1=n*m*2+1) or (k2=0) then exit(k2); num:=0; i:=p[k1]; while i<>-1 do begin j:=b[i].point; if (b[i].f>0) and (dst[j]=dst[k1]+1) then begin k:=change(j,min(k2,b[i].f)); k2:=k2-k; num:=num+k; dec(b[i].f,k); inc(b[i xor 1].f,k); if k2=0 then break; end; i:=b[i].next; end; if num=0 then dst[k1]:=-1; exit(num); end; function bfs:boolean; var i,j,head,now:longint; begin fillchar(dst,sizeof(dst),-1); fillchar(pd,sizeof(pd),false); head:=1; now:=0; pd[0]:=true; s[1]:=0; dst[0]:=0; while head>now do begin inc(now); i:=p[s[now]]; while i<>-1 do begin j:=b[i].point; if (pd[j]=false) and (b[i].f>0) then begin dst[j]:=dst[s[now]]+1; pd[j]:=true; if j=n*m*2+1 then exit(true); inc(head); s[head]:=j; end; i:=b[i].next; end; end; exit(pd[n*m*2+1]); end; procedure ade(k1,k2,k3:longint); begin inc(len); b[len].point:=k2; b[len].next:=p[k1]; b[len].f:=k3; p[k1]:=len; end; procedure add(k1,k2,k3:longint); begin ade(k1,k2,k3); ade(k2,k1,0); end; function dinic:longint; var num:longint; begin num:=0; while bfs=true do num:=num+change(0,maxlongint); exit(num); end; begin readln(n,m,r,c); fillchar(p,sizeof(p),-1); fillchar(b,sizeof(b),0); len:=-1; for i:=1 to n do for j:=1 to m do begin getchar(ch); if ch='.' then bo[i,j]:=true else bo[i,j]:=false; end; for i:=1 to n do for j:=1 to m do begin if (i+c<=n) and (j+r<=m) and (bo[i,j]=true) and (bo[i+c,j+r]=true) then add(i*m+j-m,(i+c)*m-m+j+r+n*m,1); if (i+r<=n) and (j+c<=m) and (bo[i,j]=true) and (bo[i+r,j+c]=true) then add(i*m+j-m,(i+r)*m-m+j+c+n*m,1); if (i+c<=n) and (j-r>0) and (bo[i,j]=true) and (bo[i+c,j-r]=true) then add(i*m+j-m,(i+c)*m-m+j-r+n*m,1); if (i+r<=n) and (j-c>0) and (bo[i,j]=true) and (bo[i+r,j-c]=true) then add(i*m+j-m,(i+r)*m-m+j-c+n*m,1); end; tot:=0; for i:=1 to n do for j:=1 to m do if bo[i,j]=true then begin inc(tot); add(0,i*m-m+j,1); add(i*m-m+j+n*m,n*m*2+1,1); end; writeln(tot-dinic); end.