首先我们可以二分一个答案时间T,这样就将最优性问题
转化为了判定性问题。下面我们考虑对于已知的T的判定
对于矩阵中所有的空点bfs一次,得出来每个点到门的距离,
然后连接空点和每个能在t时间内到达的门一条边,容量为1,
之后连接源和每个空点一条边,容量为1,门连接汇边,容量为t。
判断最大流是否满流就好了。
/************************************************************** Problem: 1189 User: BLADEVIL Language: Pascal Result: Accepted Time:24 ms Memory:20080 kb ****************************************************************/ //By BLADEVIL type rec =record x, y :longint; end; var n, m :longint; pre, other, len, time :array[0..1000010] of longint; last :array[0..1000010] of longint; l :longint; que1 :array[0..20000] of rec; dis :array[0..30,0..30] of longint; go :array[0..2,0..4] of longint; num :array[0..30,0..30] of longint; source, sink :longint; sum :longint; map :array[0..30,0..30] of char; que, d :array[0..20000] of longint; function min(a,b:longint):longint; begin if a>b then min:=b else min:=a; end; procedure connect(a,b,c,d:longint); begin inc(l); pre[l]:=last[a]; last[a]:=l; other[l]:=b; len[l]:=c; time[l]:=d; end; procedure make(a,b:longint); var h, t, curx, cury, nx, ny :longint; i, j :longint; f :boolean; begin connect(source,num[a,b],1,0); connect(num[a,b],source,0,0); fillchar(dis,sizeof(dis),0); dis[a,b]:=1; que1[1].x:=a; que1[1].y:=b; h:=0; t:=1; while hdo begin inc(h); curx:=que1[h].x; cury:=que1[h].y; for i:=1 to 4 do begin nx:=curx+go[1,i]; ny:=cury+go[2,i]; if (nx<1) or (nx>n) or (ny<1) or (ny>m) then continue; if dis[nx,ny]<>0 then continue; if map[nx,ny]='X' then continue; inc(t); que1[t].x:=nx; que1[t].y:=ny; dis[nx,ny]:=dis[curx,cury]+1; end; end; f:=false; for i:=1 to n do for j:=1 to m do if map[i,j]='D' then if dis[i,j]<>0 then begin f:=true; connect(num[a,b],num[i,j],1,dis[i,j]-1); connect(num[i,j],num[a,b],0,dis[i,j]-1); end; if not f then begin writeln('impossible'); halt; end; end; procedure init; var i, j :longint; begin go[1,1]:=-1; go[2,2]:=1; go[1,3]:=1; go[2,4]:=-1; readln(n,m); for i:=1 to n do begin for j:=1 to m do read(map[i,j]); readln; end; for i:=1 to n do for j:=1 to m do num[i,j]:=(i-1)*m+j; source:=2*n*m+2; sink:=source+1; l:=1; for i:=1 to n do for j:=1 to m do if map[i,j]='.' then begin make(i,j); inc(sum); end; for i:=1 to n do for j:=1 to m do if map[i,j]='D' then begin connect(num[i,j],sink,1,0); connect(sink,num[i,j],0,0); end; end; function bfs(up:longint):boolean; var q, p :longint; h, t, cur :longint; begin fillchar(d,sizeof(d),0); que[1]:=source; h:=0; t:=1; d[source]:=1; while h do begin inc(h); cur:=que[h]; q:=last[cur]; while q<>0 do begin if (len[q]>0) and (time[q]<=up) then begin p:=other[q]; if (d[p]=0) then begin inc(t); que[t]:=p; d[p]:=d[cur]+1; if p=sink then exit(true); end; end; q:=pre[q]; end; end; exit(false); end; function dinic(x,flow,up:longint):longint; var tmp, rest :longint; q, p :longint; begin rest:=flow; if x=sink then exit(flow); q:=last[x]; while q<>0 do begin p:=other[q]; if (len[q]>0) and (time[q]<=up) and (rest>0) and (d[x]=d[p]-1) then begin tmp:=dinic(p,min(len[q],rest),up); dec(rest,tmp); dec(len[q],tmp); inc(len[q xor 1],tmp); end; q:=pre[q]; end; exit(flow-rest); end; function judge(mid:longint):boolean; var q :longint; tot :longint; i :longint; begin q:=last[sink]; while q<>0 do begin len[q]:=0; len[q xor 1]:=mid; q:=pre[q]; end; tot:=0; while bfs(mid) do tot:=tot+dinic(source,maxlongint,mid); for i:=1 to l do if i mod 2=0 then begin inc(len[i],len[i xor 1]); len[i xor 1]:=0; end; if tot then exit(false) else exit(true); end; procedure main; var l, r, mid, ans :longint; begin l:=1; r:=2000; while l<=r do begin mid:=(l+r) div 2; if judge(mid) then begin ans:=mid; r:=mid-1; end else l:=mid+1; end; writeln(ans); end; begin init; main; end.