初看这题好像跟我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.
View Code

 

posted on 2014-04-16 23:08  acphile  阅读(308)  评论(0编辑  收藏  举报