zoukankan      html  css  js  c++  java
  • 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 }
  • 相关阅读:
    哥也能写KMP了——实现strstr()
    面试归来,感觉无望,下次再战
    Pow(x, n)
    Length of Last Word
    后缀数组应用
    2倍倍增算法构造后缀数组
    跳台阶问题
    求无序数组中第二大的数--快速选择
    单源最短路径问题
    全局下的isFinite
  • 原文地址:https://www.cnblogs.com/Itst/p/9889482.html
Copyright © 2011-2022 走看看