Luogu3191 HNOI2007 紧急疏散 二分答案、最大流

传送门

题意:自己去看


考虑二分答案。$BFS$预处理出每一个人到每一扇门的最短时间,设二分的值为$mid$,那么把门拆成$mid$个点,每一个点代表第$1,2,...,mid$秒时的状态。$i-1$时刻的门向$i$时刻的门连一条流量为$INF$的边,表示有无限多的人可以在门口等待。每一个门拆出来的$mid$个点向汇点连流量为$1$的边表示逃出的一个人;源点向每一个人连一条流量为$1$的边,每一个人对应的点向每一扇门的最早到达时刻对应的点连一条流量为$1$的边,最后计算最大流是否等于人数即可。

  1 #include<bits/stdc++.h>
  2 #define MAXN 7010
  3 #define XX now.x + dir[i][0]
  4 #define YY now.y + dir[i][1]
  5 #define INF 0x7fffffff
  6 using namespace std;
  7 
  8 struct Edge{
  9     int end , upEd , flow;
 10 }Ed[MAXN << 6];
 11 struct node{
 12     int x , y , flo;
 13 }now;
 14 const int dir[4][2] = {0,1,0,-1,1,0,-1,0};
 15 int head[MAXN] , flo[MAXN] , cur[MAXN] , cntEd , cntBlock , N , M , cntDoor , dis[401][161] , mid;
 16 map < pair < int , int > , int > door;
 17 char c[21][21];
 18 bool vis[21][21] , be[MAXN];
 19 queue < int > q1;
 20 queue < node > q2;
 21 
 22 void bfs(int x , int y){
 23     cntBlock++;
 24     memset(dis[cntBlock] , 0x3f , sizeof(dis[cntBlock]));
 25     q2.push((node){x , y , 0});
 26     memset(vis , 0 , sizeof(vis));
 27     vis[x][y] = 1;
 28     while(!q2.empty()){
 29         now = q2.front();
 30         q2.pop();
 31         for(int i = 0 ; i < 4 ; i++)
 32             if(c[XX][YY] != 'X' && !vis[XX][YY]){
 33                 vis[XX][YY] = 1;
 34                 if(c[XX][YY] == 'D')
 35                     dis[cntBlock][door.find(make_pair(XX , YY))->second] = now.flo + 1;
 36                 else
 37                     q2.push((node){XX , YY , now.flo + 1});
 38             }
 39     }
 40 }
 41 
 42 bool div(){
 43     while(!q1.empty())
 44         q1.pop();
 45     memset(be , 0 , sizeof(be));
 46     q1.push(0);
 47     be[0] = flo[0] = 1;
 48     while(!q1.empty()){
 49         int t = q1.front();
 50         q1.pop();
 51         for(int i = head[t] ; i ; i = Ed[i].upEd){
 52             if(!be[Ed[i].end] && Ed[i].flow){
 53                 flo[Ed[i].end] = flo[t] + 1;
 54                 be[Ed[i].end] = 1;
 55                 if(Ed[i].end == cntBlock + cntDoor * mid + 1){
 56                     memcpy(cur , head , sizeof(head));
 57                     return 1;
 58                 }
 59                 q1.push(Ed[i].end);
 60             }
 61         }
 62     }
 63     return 0;
 64 }
 65 
 66 bool dinic(int now){
 67     if(now == cntBlock + cntDoor * mid + 1)
 68         return 1;
 69     for(int &i = cur[now] ; i ; i = Ed[i].upEd)
 70         if(flo[Ed[i].end] == flo[now] + 1 && Ed[i].flow)
 71             if(dinic(Ed[i].end)){
 72                 Ed[i].flow--;
 73                 Ed[i ^ 1].flow++;
 74                 return 1;
 75             }
 76     return 0;
 77 }
 78 
 79 inline void addEd(int a , int b , int c){
 80     Ed[++cntEd].end = b;
 81     Ed[cntEd].flow = c;
 82     Ed[cntEd].upEd = head[a];
 83     head[a] = cntEd;
 84 }
 85 
 86 bool check(){
 87     memset(head , 0 , sizeof(head));
 88     cntEd = 1;
 89     int T = cntDoor * mid + cntBlock + 1;
 90     for(int i = 0 ; i < cntDoor ; i++)
 91         for(int j = 1 ; j < mid ; j++){
 92             addEd(mid * i + j + cntBlock , mid * i + j + cntBlock + 1 , INF);
 93             addEd(mid * i + j + cntBlock + 1 , mid * i + j + cntBlock , 0);
 94         }
 95     for(int i = 0 ; i < cntDoor ; i++)
 96         for(int j = 1 ; j <= mid ; j++){
 97             addEd(mid * i + j + cntBlock , T , 1);
 98             addEd(T , mid * i + j + cntBlock , 0);
 99         }
100     int cnt = 0;
101     for(int i = 2 ; i < N ; i++)
102         for(int j = 2 ; j < M ; j++)
103             if(c[i][j] == '.'){
104                 cnt++;
105                 for(int k = 1 ; k <= cntDoor ; k++)
106                     if(dis[cnt][k] <= mid){
107                         addEd(cnt , mid * (k - 1) + dis[cnt][k] + cntBlock , 1);
108                         addEd(mid * (k - 1) + dis[cnt][k] + cntBlock , cnt , 0);
109                     }
110                 addEd(0 , cnt , 1);
111                 addEd(cnt , 0 , 0);
112             }
113     int ans = 0;
114     while(div())
115         while(dinic(0))
116             ans++;
117     return ans == cntBlock;
118 }
119 
120 int main(){
121     cin >> N >> M;
122     for(int i = 1 ; i <= N ; i++)
123         for(int j = 1 ; j <= M ; j++){
124             cin >> c[i][j];
125             if(c[i][j] == 'D')
126                 door.insert(make_pair(make_pair(i , j) , ++cntDoor));
127         }
128     for(int i = 2 ; i < N ; i++)
129         for(int j = 2 ; j < M ; j++)
130             if(c[i][j] == '.')
131                 bfs(i , j);
132     int L = 0 , R = N * M;
133     while(L < R){
134         mid = L + R >> 1;
135         check() ? R = mid : L = mid + 1;
136     }
137     if(R == N * M)
138         cout << "impossible";
139     else
140         cout << R;
141     return 0;
142 }
posted @ 2018-11-01 15:23  cjoier_Itst  阅读(273)  评论(1编辑  收藏  举报