题意:自己去看
考虑二分答案。$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 }