BZOJ1189: [HNOI2007]紧急疏散evacuate(二分答案,最大流)

Description

发生了火警,所有人员需要紧急疏散!假设每个房间是一个N M的矩形区域。每个格子如果是'.',那么表示这是一
块空地;如果是'X',那么表示这是一面墙,如果是'D',那么表示这是一扇门,人们可以从这儿撤出房间。已知门
一定在房间的边界上,并且边界上不会有空地。最初,每块空地上都有一个人,在疏散的时候,每一秒钟每个人都
可以向上下左右四个方向移动一格,当然他也可以站着不动。疏散开始后,每块空地上就没有人数限制了(也就是
说每块空地可以同时站无数个人)。但是,由于门很窄,每一秒钟只能有一个人移动到门的位置,一旦移动到门的
位置,就表示他已经安全撤离了。现在的问题是:如果希望所有的人安全撤离,最短需要多少时间?或者告知根本
不可能。

Input

第一行是由空格隔开的一对正整数N与M,3<=N <=20,3<=M<=20,
以下N行M列描述一个N M的矩阵。其中的元素可为字符'.'、'X'和'D',且字符间无空格。

Output

只有一个整数K,表示让所有人安全撤离的最短时间,
如果不可能撤离,那么输出'impossible'(不包括引号)。

Sample Input

5 5
XXXXX
X...D
XX.XX
X..XX
XXDXX

Sample Output

3
解题思路:
考虑每个点到每个门的最短路一定所以先Bfs/Dijstra一遍得到每个点到每个门到最短距离。
考虑随着时间的推移,每个点能够到达的门也就越多,所以可以说是动态加边。
这时的正确方法是二分答案,建图网络流。
显然是源点连人,在时间允许的情况下人连门,容量为1。门连汇点,容量为T。
这样做理论上是很好的,但是有一个问题,那就是本题的特殊性,每个格子可以重复走人但是门只能一个一个出。
这就十分不和谐了,因为上面的做法并不能处理两个人同时到达的情况。
考虑一个问题,到底是什么性质没有被体现导致建图瑕疵。
这里可以认为门在T时刻关闭,那么本质上每个人都有一个剩余时间,假如说一起到然后一个一个出,
这里的问题就是假如说一起到的人比较多,假如说大于T那么一定不能全部出去。
所以需要有一个条件来限制每个人到达时还剩多少时间,换句话说,需要表现他究竟是什么时间到达的。
这样,将每个门拆成T个点,代表该时刻到达的门(相当于给门分层)。
每个点向到达时间的门连边,每层门向下一层连流量为$inf$的边。
跑最大流验证就好了。
代码:
  1 #include<queue>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 const int oo=0x3f3f3f3f;
  6 struct int_2{int TIME;int NO;};
  7 struct pnt{
  8     int hd;
  9     int lyr;
 10     int now;
 11 }p[1000000];
 12 struct ent{
 13     int twd;
 14     int vls;
 15     int lst;
 16     int his;
 17 }e[5000000];
 18 struct OVO{
 19     int_2 pro;
 20     int i;
 21     int j;
 22 };
 23 int cnt;
 24 int n,m;
 25 int s,t;
 26 int pnum;
 27 char tmp[100];
 28 int no[21][21];
 29 int mp[21][21];
 30 bool vis[21][21];
 31 bool hvv[21][21];
 32 std::queue<int>Q;
 33 std::queue<OVO>P;
 34 std::vector<int>T[1000];
 35 std::vector<int_2>dr[21][21];
 36 void ade(int f,int t,int v)
 37 {
 38     cnt++;
 39     e[cnt].twd=t;
 40     e[cnt].vls=v;
 41     e[cnt].his=v;
 42     e[cnt].lst=p[f].hd;
 43     p[f].hd=cnt;
 44     return ;
 45 }
 46 bool bfs(void)
 47 {
 48     for(int i=1;i<=n;i++)
 49     {
 50         for(int j=1;j<=m;j++)
 51         {
 52             if(mp[i][j]==2)
 53             {
 54                 while(!P.empty())
 55                     P.pop();
 56                 P.push((OVO){(int_2){0,no[i][j]},i,j});
 57                 while(!P.empty())
 58                 {
 59                     OVO x=P.front();
 60                     P.pop();
 61                     int ii=x.i;
 62                     int jj=x.j;
 63                     if(vis[ii][jj])
 64                         continue;
 65                     vis[ii][jj]=true;
 66                     if(mp[ii][jj]==1)
 67                         dr[ii][jj].push_back(x.pro);
 68                     x.pro.TIME++;
 69                     OVO y;
 70                     y=x;
 71                     y.i++;
 72                     if(y.i<=n)
 73                     {
 74                         if(mp[y.i][y.j]==1)
 75                         {
 76                             P.push(y);
 77                         }
 78                     }
 79                     y=x;
 80                     y.i--;
 81                     if(y.i>0)
 82                     {
 83                         if(mp[y.i][y.j]==1)
 84                         {
 85                             P.push(y);
 86                         }
 87                     }
 88                     y=x;
 89                     y.j++;
 90                     if(y.j<=m)
 91                     {
 92                         if(mp[y.i][y.j]==1)
 93                         {
 94                             P.push(y);
 95                         }
 96                     }
 97                     y=x;
 98                     y.j--;
 99                     if(y.j>0)
100                     {
101                         if(mp[y.i][y.j]==1)
102                         {
103                             P.push(y);
104                         }
105                     }
106                 }
107                 for(int ii=1;ii<=n;ii++)
108                 {
109                     for(int jj=1;jj<=m;jj++)
110                     {
111                         if(vis[ii][jj])
112                             hvv[ii][jj]=true;
113                         vis[ii][jj]=false;
114                     }
115                 }
116             }
117         }
118     }
119     for(int i=1;i<=n;i++)
120     {
121         for(int j=1;j<=m;j++)
122         {
123             if(!hvv[i][j]&&mp[i][j]==1)
124                 return true;
125         }
126     }
127     return false;
128 }
129 bool Bfs(void)
130 {
131     while(!Q.empty())Q.pop();
132     for(int i=1;i<=t;i++)
133         p[i].lyr=0;
134     p[s].lyr=1;
135     Q.push(s);
136     while(!Q.empty())
137     {
138         int x=Q.front();
139         Q.pop();
140         for(int i=p[x].hd;i;i=e[i].lst)
141         {
142             int to=e[i].twd;
143             if(p[to].lyr==0&&e[i].vls>0)
144             {
145                 p[to].lyr=p[x].lyr+1;
146                 if(to==t)
147                     return true;
148                 Q.push(to);
149             }
150         }
151     }
152     return false;
153 }
154 int Dfs(int x,int fll)
155 {
156     if(x==t)
157         return fll;
158     for(int& i=p[x].now;i;i=e[i].lst)
159     {
160         int to=e[i].twd;
161         if(p[to].lyr==p[x].lyr+1&&e[i].vls>0)
162         {
163             int ans=Dfs(to,std::min(fll,e[i].vls));
164             if(ans>0)
165             {
166                 e[i].vls-=ans;
167                 e[((i-1)^1)+1].vls+=ans;
168                 return ans;
169             }
170         }
171     }
172     return 0;
173 }
174 int Dinic(void)
175 {
176     int ans=0;
177     while(Bfs())
178     {
179         for(int i=1;i<=t;i++)
180             p[i].now=p[i].hd;
181         int dlt;
182         while(dlt=Dfs(s,oo))
183             ans+=dlt;
184     }
185     return ans;
186 }
187 bool Check(int x)
188 {
189     for(int i=1;i<=t;i++)
190         p[i].hd=0;
191     cnt=0;
192     int lcnt=n*m;
193     for(int i=1;i<=n;i++)
194         for(int j=1;j<=m;j++)
195             if(mp[i][j]==2)
196             {
197                 T[no[i][j]].clear();
198                 for(int k=0;k<=x;k++)
199                     T[no[i][j]].push_back(++lcnt);
200             }
201     s=lcnt+1;
202     t=s+1;
203     for(int i=1;i<=n;i++)
204     {
205         for(int j=1;j<=m;j++)
206         {
207             if(mp[i][j]==1)
208             {
209                 ade(s,no[i][j],1);
210                 ade(no[i][j],s,0);
211                 for(int k=0;k<dr[i][j].size();k++)
212                 {
213                     if(dr[i][j][k].TIME<=x)
214                     {
215                         ade(no[i][j],T[dr[i][j][k].NO][dr[i][j][k].TIME],1);
216                         ade(T[dr[i][j][k].NO][dr[i][j][k].TIME],no[i][j],0);
217                     }
218                 }
219             }else if(mp[i][j]==2)
220             {
221                 for(int k=0;k<=x;k++)
222                 {
223                     ade(T[no[i][j]][k],t,1);
224                     ade(t,T[no[i][j]][k],0);
225                     if(k!=x)
226                     {
227                         ade(T[no[i][j]][k],T[no[i][j]][k+1],oo);
228                         ade(T[no[i][j]][k+1],T[no[i][j]][k],0);
229                     }
230                 }
231             }
232         }
233     }
234     return pnum==Dinic();
235 }
236 int main()
237 {
238 //    freopen("a.in","r",stdin);
239     scanf("%d%d",&n,&m);
240     for(int i=1;i<=n;i++)
241     {
242         scanf("%s",tmp+1);
243         for(int j=1;j<=m;j++)
244         {
245             no[i][j]=++cnt;
246             if(tmp[j]=='X')
247                 mp[i][j]=0;
248             if(tmp[j]=='.')
249                 mp[i][j]=1,
250                 pnum++;
251             if(tmp[j]=='D')
252                 mp[i][j]=2;
253         }
254     }
255     cnt=0;
256     if(bfs())
257     {
258         puts("impossible");
259         return 0;
260     }
261     int l=0,r=1000;
262     int ans;
263     while(l<=r)
264     {
265         int mid=(l+r)>>1;
266         if(Check(mid))
267         {
268             ans=mid;
269             r=mid-1;
270         }else
271             l=mid+1;
272     }
273     printf("%d\n",ans);
274     return 0;
275 }

 

posted @ 2019-01-08 14:46  Unstoppable728  阅读(277)  评论(0编辑  收藏  举报