题目大意:紧急疏散。有一张地图,‘.’表示人,‘D’表示门,人需要走曼哈顿距离的单位时间才1能到达门。一个门一个时刻只能通过一个人。求多长时间能疏散完毕。
思路:二分答案+最大流满流判定。先BFS处理出每个人与门的距离。二分最小时间,然后连边。S向每个人连流量为1的边,每个人向二分的时间之内能到达的门连流量为1的边。每个门向T连流量为t的边。然后最大流判定是否满流。
(数组大小我是瞎开的,写代码的时候要算好了在开!)
CODE:
#include <queue> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define MAX 10010 #define S 0 #define T 5000 #define INF 0x7f7f7f7f using namespace std; const int dx[] = {0,0,0,1,-1}; const int dy[] = {0,1,-1,0,0}; struct Door{ int x,y; Door(int _,int __):x(_),y(__) {} Door() {} }door[MAX]; struct Empty{ int x,y; Empty(int _,int __):x(_),y(__) {} Empty() {} }person[MAX]; struct Status{ int x,y; int length; Status(int _,int __,int ___) :x(_),y(__),length(___) {} Status() {} }; int m,n; int doors,persons; char src[30][30]; int num[30][30],dis[MAX][410]; bool v[30][30]; int head[MAX],total; int _next[2000000],aim[2000000],flow[2000000]; int deep[MAX]; inline void BFS(int p); inline void MakeGraph(int t); inline void Initialize(); inline void Add(int x,int y,int f); bool BFS(); int Dinic(int x,int f); int main() { cin >> m >> n; for(int i = 1;i <= m; ++i) { scanf("%s",src[i] + 1); for(int j = 1;j <= n; ++j) { if(src[i][j] == 'D') { door[++doors] = Door(i,j); num[i][j] = doors; } else if(src[i][j] == '.') { person[++persons] = Empty(i,j); num[i][j] = persons; } } } memset(dis,0x3f,sizeof(dis)); for(int i = 1;i <= doors; ++i) BFS(i); int l = 0,r = 400,ans = -1; while(l <= r) { int mid = (l + r) >> 1; MakeGraph(mid); int max_flow = 0; while(BFS()) max_flow += Dinic(S,INF); if(max_flow == persons) ans = mid,r = mid - 1; else l = mid + 1; } if(ans == -1) puts("impossible"); else cout << ans << endl; return 0; } inline void BFS(int p) { static queue<Status> q; while(!q.empty()) q.pop(); memset(v,false,sizeof(v)); q.push(Status(door[p].x,door[p].y,0)); while(!q.empty()) { Status now = q.front(); q.pop(); v[now.x][now.y] = true; for(int i = 1;i <= 4; ++i) { int fx = now.x + dx[i]; int fy = now.y + dy[i]; if(v[fx][fy] || !fx || !fy || fx > m || fy > n) continue; if(src[fx][fy] == '.') { dis[num[fx][fy]][p] = now.length + 1; q.push(Status(fx,fy,now.length + 1)); } } } } inline void MakeGraph(int t) { Initialize(); for(int i = 1;i <= persons; ++i) Add(S,i,1),Add(i,S,0); for(int i = persons + 1;i <= persons + doors; ++i) Add(i,T,t),Add(T,i,0); for(int i = 1;i <= persons; ++i) for(int j = 1;j <= doors; ++j) if(dis[i][j] <= t) Add(i,j + persons,1),Add(j + persons,i,0); } inline void Initialize() { total = 1; memset(head,0,sizeof(head)); } inline void Add(int x,int y,int f) { _next[++total] = head[x]; aim[total] = y; flow[total] = f; head[x] = total; } bool BFS() { static queue<int> q; while(!q.empty()) q.pop(); memset(deep,0,sizeof(deep)); deep[S] = 1; q.push(S); while(!q.empty()) { int x = q.front(); q.pop(); for(int i = head[x];i;i = _next[i]) if(flow[i] && !deep[aim[i]]) { deep[aim[i]] = deep[x] + 1; q.push(aim[i]); if(aim[i] == T) return true; } } return false; } int Dinic(int x,int f) { if(x == T) return f; int temp = f; for(int i = head[x];i;i = _next[i]) if(flow[i] && temp && deep[aim[i]] == deep[x] + 1) { int away = Dinic(aim[i],min(flow[i],temp)); flow[i] -= away; flow[i^1] += away; temp -= away; } if(temp == f) deep[x] = 0; return f - temp; }
BZOJ 1189 HNOI 2007 紧急疏散 evacuate 二分答案 最大流
原文地址:http://blog.csdn.net/jiangyuze831/article/details/39737175