初看这题好像跟我mincost第一题很像,多了点门其实最短路/bfs与处理一下就可以了
但是门只能容纳一个人
所以,也就是说,费用是变的,怎么做?
仔细想想,费用流好像不能处理费用改变的
扔掉费用流,首先决策具有单调性,二分!
当我们确定了时间之后,我们怎么快速的判断可行呢?
由于门每分钟只能容纳一个人,也就是说,在这分钟内这个门只能被一个人匹配
不禁想到了最大流/二分图匹配,暴力将每个门拆成对应时间点
每个人对应能走的门连边然后匈牙利即可
到这问题好像解决了(实际上也解决了);
但我写着写着发现一个问题
一开始的预处理,似乎不能简单的求每点到每个门的最短距离
因为看起来有的门能到,实际却到不了
比如
XXDDX
XXX.X
X...X
X...X
XXXXX
比如(1,3)的门是根本走不到的,被另一个门挡住了
而且这是会影响结果的(在一个门被堵住,肯定要分流去另一个门)
但我也没管,后来发现数据里好像也没这种情况(……)
就这样吧
一般的,费用流的费用都是不变的吧,否则都应该转化为二分+最大流判定吧
为了方便我写了二分图匹配快一些
1 const dx:array[1..4] of integer=(0,0,-1,1); 2 dy:array[1..4] of integer=(1,-1,0,0); 3 inf=10000007; 4 type node=record 5 point,next:longint; 6 end; 7 8 var a,map,dis:array[0..1010,0..1010] of longint; 9 q:array[0..2000010] of longint; 10 cx,d,p,b:array[0..1010] of longint; 11 cy:array[0..1001000] of longint; //注意二分图另一个点集规模 12 edge:array[0..5000010] of node; 13 v:array[0..1001010] of boolean; 14 k,ans,len,pep,sum,x,y,l,r,mid,n,m,t,i,j:longint; 15 ch:char; 16 17 procedure add(x,y:longint); 18 begin 19 inc(len); 20 edge[len].point:=y; 21 edge[len].next:=p[x]; 22 p[x]:=len; 23 end; 24 25 procedure spfa(k:longint); 26 var s,i,x,f,r:longint; 27 begin 28 f:=1; 29 r:=1; 30 for i:=1 to t do 31 d[i]:=inf; 32 s:=b[k]; 33 d[s]:=0; 34 fillchar(v,sizeof(v),false); 35 v[s]:=true; 36 q[1]:=s; 37 while f<=r do 38 begin 39 x:=q[f]; 40 v[x]:=false; 41 for i:=1 to t do 42 if map[x,i]>0 then 43 if d[i]>d[x]+map[x,i] then 44 begin 45 d[i]:=d[x]+map[x,i]; 46 if not v[i] then 47 begin 48 inc(r); 49 q[r]:=i; 50 v[i]:=true; 51 end; 52 end; 53 inc(f); 54 end; 55 for i:=1 to pep do 56 dis[i,k]:=d[i]; 57 end; 58 59 function dfs(x:longint):boolean; 60 var i,j:longint; 61 begin 62 i:=p[x]; 63 while i<>-1 do 64 begin 65 j:=edge[i].point; 66 if not v[j] then 67 begin 68 v[j]:=true; 69 if (cy[j]=-1) or dfs(cy[j]) then 70 begin 71 cy[j]:=x; 72 cx[x]:=j; 73 exit(true); 74 end; 75 end; 76 i:=edge[i].next; 77 end; 78 exit(false); 79 end; 80 81 function check(k:longint):boolean; 82 var s,i,j,w,z:longint; 83 begin 84 len:=0; 85 fillchar(p,sizeof(p),255); 86 for i:=1 to pep do 87 begin 88 for j:=1 to sum do 89 if dis[i,j]<=k then 90 begin 91 for w:=0 to k-dis[i,j] do 92 begin 93 z:=(j-1)*k+dis[i,j]+w; //暴力拆点 94 add(i,z); 95 end; 96 end; 97 end; 98 fillchar(cx,sizeof(cx),255); 99 fillchar(cy,sizeof(cy),255); 100 for i:=1 to pep do 101 begin 102 fillchar(v,sizeof(v),false); 103 if not dfs(i) then exit(false); //匹配 104 end; 105 exit(true); 106 end; 107 108 begin 109 readln(n,m); 110 fillchar(a,sizeof(a),0); 111 for i:=1 to n do 112 begin 113 for j:=1 to m do 114 begin 115 read(ch); 116 if ch='.' then 117 begin 118 inc(pep); 119 a[i,j]:=pep; 120 end 121 else if ch='D' then 122 begin 123 inc(sum); 124 a[i,j]:=-sum; 125 end; 126 end; 127 readln; 128 end; 129 sum:=0; 130 for i:=1 to n do 131 for j:=1 to m do 132 if a[i,j]<0 then 133 begin 134 inc(sum); 135 a[i,j]:=abs(a[i,j])+pep; 136 b[sum]:=a[i,j]; 137 end; 138 139 for i:=1 to n do //其实是有问题的预处理 140 for j:=1 to m do 141 if a[i,j]>0 then 142 begin 143 for k:=1 to 4 do 144 begin 145 x:=i+dx[k]; 146 y:=j+dy[k]; 147 if a[x,y]>0 then 148 begin 149 map[a[i,j],a[x,y]]:=1; 150 map[a[i,j],a[x,y]]:=1; 151 end; 152 end; 153 end; 154 t:=pep+sum; 155 156 for i:=1 to sum do 157 spfa(i); 158 l:=1; 159 r:=1000; 160 ans:=0; 161 while l<=r do 162 begin 163 mid:=(l+r) shr 1; 164 if check(mid) then 165 begin 166 ans:=mid; 167 r:=mid-1; 168 end 169 else l:=mid+1; 170 end; 171 if ans=0 then writeln('impossible') 172 else writeln(ans); 173 end.