[题目链接]
https://www.lydsy.com/JudgeOnline/problem.php?id=1189
[算法]
首先 , 答案具有单调性 , 不妨二分答案” 第mid秒是否可以完成疏散 ”
检验时 , 首先通过广度优先搜索BFS求出每扇门到每个空地的距离
然后建图 , 判断最大流是否等于空地的数量
详见代码
时间复杂度: O(dinic(N ^ 3 , N ^ 3) log N ^ 2)
[代码]
#include<bits/stdc++.h> using namespace std; #define MAXN 16100 #define MAXD 25 const int inf = 2e9; const int dx[4] = {0 , 0 , -1 , 1}; const int dy[4] = {-1 , 1 , 0 , 0}; struct edge { int to , w , nxt; } e[MAXN << 1]; int tot , cntk , cntd , S , T , n , m; int head[MAXN] , depth[MAXN]; int point[MAXD][MAXD]; int dist[MAXN][MAXD][MAXD]; char mp[MAXD][MAXD]; pair<int , int> a[MAXN * MAXD]; template <typename T> inline void chkmax(T &x,T y) { x = max(x,y); } template <typename T> inline void chkmin(T &x,T y) { x = min(x,y); } template <typename T> inline void read(T &x) { T f = 1; x = 0; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -f; for (; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + c - '0'; x *= f; } inline void addedge(int u , int v , int w) { ++tot; e[tot] = (edge){v , w , head[u]}; head[u] = tot; ++tot; e[tot] = (edge){u , 0 , head[v]}; head[v] = tot; } inline bool valid(int x , int y) { return x >= 1 && x <= n && y >= 1 && y <= m; } inline void do_bfs(int s) { queue< pair<int , int> > q; q.push(make_pair(a[s].first , a[s].second)); memset(dist[s] , 0x3f , sizeof(dist[s])); dist[s][a[s].first][a[s].second] = 0; while (!q.empty()) { pair<int , int> cur = q.front(); q.pop(); for (int i = 0; i < 4; i++) { int nx = cur.first + dx[i] , ny = cur.second + dy[i]; if (valid(nx , ny) && mp[nx][ny] == '.') { if (dist[s][cur.first][cur.second] + 1 < dist[s][nx][ny]) { dist[s][nx][ny] = dist[s][cur.first][cur.second] + 1; q.push(make_pair(nx , ny)); } } } } } inline bool bfs() { int l , r; static int q[MAXN]; q[l = r = 1] = S; memset(depth , 0 ,sizeof(depth)); depth[S] = 1; while (l <= r) { int cur = q[l++]; for (int i = head[cur]; i; i = e[i].nxt) { int v = e[i].to , w = e[i].w; if (w > 0 && !depth[v]) { depth[v] = depth[cur] + 1; q[++r] = v; if (v == T) return true; } } } return false; } inline int dinic(int u , int flow) { int rest = flow , ret = 0; if (u == T) return flow; for (int i = head[u]; i && rest; i = e[i].nxt) { int v = e[i].to , w = e[i].w; if (depth[v] == depth[u] + 1 && w) { int k = dinic(v , min(rest , w)); if (!k) depth[v] = 0; e[i].w -= k; e[i ^ 1].w += k; rest -= k; } } return flow - rest; } inline bool check(int mid) { S = cntk + cntd * mid + cntd + 1; T = S + 1; tot = 0; for (int i = 1; i <= T; i++) head[i] = 0; for (int i = 1; i <= n; i++) { for (int j = 1; j <= m; j++) { if (mp[i][j] == '.') addedge(S , point[i][j] , 1); } } for (int i = 1; i <= cntd; i++) { for (int j = 1; j <= n; j++) { for (int k = 1; k <= m; k++) { if (mp[j][k] == '.' && dist[i][j][k] <= mid) addedge(point[j][k] , cntk + (i - 1) * mid + dist[i][j][k] , 1); } } } for (int i = 1; i <= cntd; i++) { for (int j = 1; j <= mid; j++) { addedge(cntk + (i - 1) * mid + j , cntk + cntd * mid + i , mid - j + 1); } } for (int i = 1; i <= cntd; i++) addedge(cntk + cntd * mid + i , T , mid); int ret = 0; while (bfs()) { while (int flow = dinic(S , inf)) ret += flow; } return ret == cntk; } int main() { scanf("%d%d" , &n , &m); for (int i = 1; i <= n; i++) scanf("%s" , mp[i] + 1); for (int i = 1; i <= n; i++) { for (int j = 1; j <= m; j++) { if (mp[i][j] == '.') point[i][j] = ++cntk; if (mp[i][j] == 'D') a[++cntd] = make_pair(i , j); } } for (int i = 1; i <= cntd; i++) do_bfs(i); int l = 0 , r = n * m , ans = -1; while (l <= r) { int mid = (l + r) >> 1; if (check(mid)) { ans = mid; r = mid - 1; } else l = mid + 1; } if (ans >= 0) printf("%d " , ans); else printf("impossible "); return 0; }