题意:
有一个n×m的房间,四周每个格子要么是墙要么是门。中间部分是墙或者人。
现在所有人要从房间逃出去,每个人的速度为1,也就是每个单位时间只能向上下左右四个方向走一格。
多个人可以站在同一个格子上,但是每个时刻每个门只能通过一格人,求所有人从房间中逃出去所需要的最少时间。
分析:
把每个人看成一个点,然后把每个时刻和门组成的二元组看成一个点。
如果两点之间连一条边表示这个人在这个时刻从这个门逃出去。
所以我们可以从小到大将时间逐渐加1,直到找到最大匹配为止。
在增加点的时候,可以在之前最大流基础上增广,这样更快。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #include <vector> 6 #include <queue> 7 #include <map> 8 #define MP make_pair 9 using namespace std; 10 11 typedef pair<int, int> PII; 12 13 const int INF = 0x3f3f3f3f; 14 const int maxh = 15; 15 const int maxnode = 20000; 16 17 char maze[maxh][maxh]; 18 int id[maxh][maxh]; 19 20 int row, col; 21 22 vector<PII> people, doors; 23 24 int dx[] = { 1, 0, -1, 0 }; 25 int dy[] = { 0, 1, 0, -1 }; 26 27 int dist[50][130]; //the distance from every door to people 28 int steps[maxh][maxh]; 29 30 bool inline in(int x, int y) { return x >= 0 && x < row && y >= 0 && y < col; } 31 32 bool vis[maxh][maxh]; 33 34 void bfs(PII s) 35 { 36 int st = id[s.first][s.second]; 37 steps[s.first][s.second] = 0; 38 queue<PII> Q; 39 Q.push(s); 40 memset(vis, false, sizeof(vis)); 41 vis[s.first][s.second] = true; 42 43 while(!Q.empty()) 44 { 45 PII t = Q.front(); Q.pop(); 46 for(int i = 0; i < 4; i++) 47 { 48 int x = t.first + dx[i]; 49 int y = t.second + dy[i]; 50 if(in(x, y) && !vis[x][y] && maze[x][y] == '.') 51 { 52 vis[x][y] = true; 53 dist[st][id[x][y]] = steps[x][y] = steps[t.first][t.second] + 1; 54 Q.push(MP(x, y)); 55 } 56 } 57 } 58 } 59 60 struct Edge 61 { 62 int from, to, cap, flow; 63 Edge(int u, int v, int c, int f):from(u), to(v), cap(c), flow(f) {} 64 }; 65 66 int nodes; 67 vector<int> G[maxnode]; 68 vector<Edge> edges; 69 70 void init() 71 { 72 edges.clear(); 73 for(int i = 0; i < nodes; i++) G[i].clear(); 74 } 75 76 void AddEdge(int u, int v, int cap) 77 { 78 edges.push_back(Edge(u, v, cap, 0)); 79 edges.push_back(Edge(v, u, 0, 0)); 80 int m = edges.size(); 81 G[u].push_back(m - 2); 82 G[v].push_back(m - 1); 83 } 84 85 int s, t; 86 bool visit[maxnode]; 87 int d[maxnode], cur[maxnode]; 88 89 bool BFS() 90 { 91 memset(visit, false, sizeof(visit)); 92 queue<int> Q; 93 Q.push(s); 94 d[s] = 0; 95 visit[s] = true; 96 97 while(!Q.empty()) 98 { 99 int u = Q.front(); Q.pop(); 100 for(int i = 0; i < G[u].size(); i++) 101 { 102 Edge& e = edges[G[u][i]]; 103 int v = e.to; 104 if(!visit[v] && e.cap > e.flow) 105 { 106 visit[v] = true; 107 Q.push(v); 108 d[v] = d[u] + 1; 109 } 110 } 111 } 112 113 return visit[t]; 114 } 115 116 int DFS(int u, int a) 117 { 118 if(u == t || a == 0) return a; 119 int flow = 0, f; 120 for(int& i = cur[u]; i < G[u].size(); i++) 121 { 122 Edge& e = edges[G[u][i]]; 123 int v = e.to; 124 if(d[v] == d[u] + 1 && (f = DFS(v, min(a, e.cap - e.flow))) > 0) 125 { 126 e.flow += f; 127 edges[G[u][i]^1].flow -= f; 128 flow += f; 129 a -= f; 130 if(a == 0) break; 131 } 132 } 133 return flow; 134 } 135 136 int Maxflow() 137 { 138 int flow = 0; 139 while(BFS()) 140 { 141 memset(cur, 0, sizeof(cur)); 142 flow += DFS(s, INF); 143 } 144 return flow; 145 } 146 147 void Readuce() 148 { 149 for(int i = 0; i < edges.size(); i++) 150 edges[i].cap -= edges[i].flow, edges[i].flow = 0; 151 } 152 153 int main() 154 { 155 int T; scanf("%d", &T); 156 while(T--) 157 { 158 scanf("%d%d", &row, &col); 159 for(int i = 0; i < row; i++) scanf("%s", maze[i]); 160 161 memset(id, 0, sizeof(id)); 162 people.clear(); doors.clear(); 163 int psz = 0, dsz = 0; 164 for(int i = 0; i < row; i++) 165 for(int j = 0; j < col; j++) 166 { 167 if(maze[i][j] == 'D') { doors.push_back(MP(i, j)); id[i][j] = dsz++; } 168 else if(maze[i][j] == '.') { people.push_back(MP(i, j)); id[i][j] = psz++; } 169 } 170 171 memset(dist, 0x3f, sizeof(dist)); 172 for(int i = 0; i < dsz; i++) bfs(doors[i]); 173 bool unreachable = false; 174 for(int i = 0; i < psz; i++) 175 { 176 bool reach = false; 177 for(int j = 0; j < dsz; j++) 178 if(dist[j][i] < INF) { reach = true; break; } 179 if(reach == false) { unreachable = true; break; } 180 } 181 182 if(unreachable) { puts("impossible"); continue; } 183 184 int tot_time = 0; 185 s = 0, t = 1; 186 nodes = 2 + psz; 187 init(); 188 for(int i = 0; i < psz; i++) AddEdge(s, i + 2, 1); 189 190 int matches = 0; 191 for(;;) 192 { 193 tot_time++; 194 for(int i = 0; i < dsz; i++) 195 { 196 G[nodes].clear(); 197 AddEdge(nodes, t, 1); 198 for(int j = 0; j < psz; j++) 199 if(dist[i][j] <= tot_time) AddEdge(j + 2, nodes, 1); 200 nodes++; 201 } 202 matches += Maxflow(); 203 if(matches == psz) break; 204 Readuce(); 205 } 206 printf("%d ", tot_time); 207 } 208 209 return 0; 210 }