博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【洛谷 P3191】 [HNOI2007]紧急疏散EVACUATE(二分答案,最大流)
阅读量:4966 次
发布时间:2019-06-12

本文共 3277 字,大约阅读时间需要 10 分钟。

sb错误调了3hour+。。
bfs预处理出每个\(.\)到每个\(D\)的最短距离。
二分时间\(t\),把每个\(D\)拆成\(t\)个点,这\(t\)个点两两连边,流量\(INF\)表示\(t\)个时刻都可以从这个\(D\)出。
然后枚举所有\(.\),再枚举所有\(D\),如果距离\(dis\)小于\(t\),就从这个\(.\)向这个\(D\)的第\(dis\)个点连一条流量为\(1\)的边,表示从这个时刻开始这个\(.\)可以从这个\(D\)出。
然后求最大流,如果等于\(.\)的个数,说明此\(t\)可行,二分一下即可。

#include 
#include
#include
#include
#define INF 2147483647using namespace std;const int MAXN = 300010;const int N = 440;const int MAXM = 200010;char a[N][N];int b[N][N], c[N][N];struct point{ int x, y, time;}Now;queue
q;queue
Q;struct Edge{ int from, to, next, rest;}e[MAXM];int head[MAXN], num = 1, s, t, now, n, m, dis[MAXN];inline void Add(int from, int to, int flow){ e[++num] = (Edge){ from, to, head[from], flow }; head[from] = num; e[++num] = (Edge){ to, from, head[to], 0 }; head[to] = num;}inline int id(int i, int j){ return (i - 1) * m + j;}int re(){ memset(dis, 0, sizeof dis); q.push(s); dis[s] = 1; while(q.size()){ now = q.front(); q.pop(); for(int i = head[now]; i; i = e[i].next) if(e[i].rest && !dis[e[i].to]) dis[e[i].to] = dis[now] + 1, q.push(e[i].to); } return dis[t];}int find(int u, int flow){ if(u == t || !flow) return flow; /*if(u == 448){ int xsxs = 1; }*/ int sum = 0, T; for(int i = head[u]; i; i = e[i].next) if(e[i].rest && dis[e[i].to] == dis[u] + 1){ T = find(e[i].to, min(flow - sum, e[i].rest)); e[i].rest -= T; e[i ^ 1].rest += T; sum += T; } if(!sum) dis[u] = 0; return sum;}int dinic(){ int ans = 0; while(re()) ans += find(s, INF); /*for(int i = 1; i <= num; ++i) if(e[i].to <= n * m && e[i].from == s) if(e[i].rest) printf("%d %d %d\n", (e[i].to - 1) / 12 + 1, e[i].to % 12 == 0 ? 12 : e[i].to % 12, e[i].to); system("pause");*/ return ans;}int cnt, tot, l[] = {233, -1, 1, 0, 0}, r[] = {666, 0, 0, -1, 1}, vis[N][N], L, R;void bfs(int x, int y){ Q.push((point){x, y, 0}); for(int i = 1; i <= n; ++i) for(int j = 1; j <= m; ++j) vis[i][j] = 0; vis[x][y] = 1; while(Q.size()){ Now = Q.front(); Q.pop(); for(int i = 1; i <= 4; ++i){ int X = Now.x + l[i], Y = Now.y + r[i]; if(!X || !Y || X > n || Y > m || a[X][Y] == 'X' || vis[X][Y]) continue; Q.push((point){X, Y, Now.time + 1}); vis[X][Y] = 1; if(b[X][Y]) c[id(x, y)][b[X][Y]] = Now.time + 1; } }}int ans, mid;int main(){ scanf("%d%d", &n, &m); s = 290000; t = 300001; for(int i = 1; i <= n; ++i) scanf("%s", a[i] + 1); for(int i = 1; i <= n; ++i) for(int j = 1; j <= m; ++j) if(a[i][j] == 'D') b[i][j] = ++cnt; else if(a[i][j] == '.') ++tot; for(int i = 1; i <= n; ++i) for(int j = 1; j <= m; ++j) if(a[i][j] == '.') bfs(i, j); L = 1; R = 400; ans = -1; if(tot) while(L <= R){ mid = (L + R) >> 1; memset(head, 0, sizeof head); num = 1; for(int i = 1; i <= n; ++i) for(int j = 1; j <= m; ++j) if(a[i][j] == '.'){ Add(s, id(i, j), 1); for(int k = 1; k <= cnt; ++k){ int d = id(i, j); if(c[d][k] && c[d][k] <= mid) Add(d, 400 + cnt * c[d][k] + k, 1); } } for(int i = 1; i <= cnt; ++i) for(int j = 1; j <= mid; ++j) Add(400 + cnt * j + i, t, 1), Add(400 + cnt * j + i, 400 + cnt * j + cnt + i, INF); if(dinic() == tot) ans = mid, R = mid - 1; else L = mid + 1; } if(ans == -1) printf("impossible\n"); else printf("%d\n", ans); return 0;}

转载于:https://www.cnblogs.com/Qihoo360/p/10539447.html

你可能感兴趣的文章
求输入成绩的平均分
查看>>
php PDO (转载)
查看>>
wordpress自动截取文章摘要代码
查看>>
[置顶] 一名优秀的程序设计师是如何管理知识的?
查看>>
scanf和gets
查看>>
highcharts 图表实例
查看>>
ubuntu下如何查看用户登录及系统授权相关信息
查看>>
秋季学期学习总结
查看>>
SpringBoot 优化内嵌的Tomcat
查看>>
【LaTeX】E喵的LaTeX新手入门教程(1)准备篇
查看>>
highcharts曲线图
查看>>
extjs动态改变样式
查看>>
PL/SQL Developer 查询的数据有乱码或者where 字段名=字段值 查不出来数据
查看>>
宏定义
查看>>
笔记:git基本操作
查看>>
生成php所需要的APNS Service pem证书的步骤
查看>>
JavaWeb之JSON
查看>>
HOT SUMMER 每天都是不一样,积极的去感受生活 C#关闭IE相应的窗口 .
查看>>
windows平台上编译mongdb-cxx-driver
查看>>
optionMenu-普通菜单使用
查看>>