BZOJ 1189 HNOI 2007 紧急疏散 evacuate 二分答案 最大流

来源:互联网 发布:东方航空网络值机 编辑:程序博客网 时间:2024/05/16 16:12

题目大意:紧急疏散。有一张地图,‘.’表示人,‘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 0x7f7f7f7fusing 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;elsel = mid + 1;}if(ans == -1)puts("impossible");elsecout << 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;}


0 0