洛谷 P3191 [HNOI2007]紧急疏散EVACUATE(网络最大流)
题解
二分答案+Dinic最大流
二分答案\(mid\)
把门拆成\(mid\)个时间点的门
相邻时间的门连一条\(inf\)的边
预处理出每个门到每个人的最短时间
为\(dis[k][i][j]\) 在\((i,j)\)的人到第\(k\)个门最短时间
然后一个人连向每个第\(dis[k][i][j]\)那个时刻的门,容量为\(1\)
然后,源点连向每个人一条容量为\(1\)的边
所有门都连向汇点一条容量为\(1\)的边(其实只要每个最后一个时刻的门连一条容量为\(mid\)的边即可)
Code
#include<bits/stdc++.h>
#define LL long long
#define RG register
using namespace std;
template<class T> inline void read(T &x) {
x = 0; RG char c = getchar(); bool f = 0;
while (c != '-' && (c < '0' || c > '9')) c = getchar(); if (c == '-') c = getchar(), f = 1;
while (c >= '0' && c <= '9') x = x*10+c-48, c = getchar();
x = f ? -x : x;
return ;
}
template<class T> inline void write(T x) {
if (!x) {putchar(48);return ;}
if (x < 0) x = -x, putchar('-');
int len = -1, z[20]; while (x > 0) z[++len] = x%10, x /= 10;
for (RG int i = len; i >= 0; i--) putchar(z[i]+48);return ;
}
const int N = 40, inf = 1e9;
int n, m;
int fx[4] = {1, 0, -1, 0};
int fy[4] = {0, 1, 0, -1};
char ch[N][N];
int dis[N<<2][N][N], door, people;
struct BB {
int x, y;
};
queue<BB> Q;
void BFS(int k, int xx, int yy) {
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
dis[k][i][j] = inf;
dis[k][xx][yy] = 0; Q.push((BB) {xx, yy});
while (!Q.empty()) {
int x = Q.front().x, y = Q.front().y; Q.pop();
for (int w = 0; w < 4; w++) {
int i = x + fx[w], j = y + fy[w];
if (i < 1 || i > n || j < 1 || j > m || ch[i][j] != '.') continue;
if (dis[k][i][j] > dis[k][x][y]+1)
dis[k][i][j] = dis[k][x][y]+1, Q.push((BB) {i, j});
}
}
}
struct node {
int to, nxt, w;
}g[N*N*N*N];
int last[N*N*N], cur[N*N*N], dep[N*N*N], s, t, gl = 1, p[N][N];
inline void add(int a, int b, int c) {
g[++gl] = (node) {b, last[a], c};
last[a] = gl;
g[++gl] = (node) {a, last[b], 0};
last[b] = gl;
}
queue<int> q;
bool bfs() {
memset(dep, 0, sizeof(dep));
q.push(s); dep[s] = 1;
while (!q.empty()) {
int u = q.front(); q.pop();
for (int i = last[u]; i; i = g[i].nxt) {
int v = g[i].to;
if (!dep[v] && g[i].w) {
dep[v] = dep[u]+1;
q.push(v);
}
}
}
return dep[t] == 0 ? 0 : 1;
}
int dfs(int u, int d) {
if (u == t) return d;
for (int &i = cur[u]; i; i = g[i].nxt) {
int v = g[i].to;
if (g[i].w && dep[v] == dep[u]+1) {
int di = dfs(v, min(d, g[i].w));
if (di) {
g[i].w -= di;
g[i^1].w += di;
return di;
}
}
}
return 0;
}
int Dinic() {
int ans = 0;
while (bfs()) {
for (int i = 1; i <= t; i++)
cur[i] = last[i];
while (int d = dfs(s, inf)) ans += d;
}
return ans;
}
int check(int mid) {
s = door*mid+people+1, t = s+1;
memset(last, 0, sizeof(last)); gl = 1;
for (int k = 1; k <= door; k++)
for (int z = 1; z <= mid; z++) {
if (z < mid)
add((k-1)*mid+z, (k-1)*mid+z+1, inf);
else add(k*mid, t, mid);
}
for (int i = 1; i <= people; i++)
add(s, door*mid+i, 1);
for (int k = 1; k <= door; k++)
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
if (ch[i][j] == '.' && dis[k][i][j] <= mid)
add(door*mid+p[i][j], (k-1)*mid+dis[k][i][j], 1);
return Dinic();
}
int main() {
read(n), read(m);
for (int i = 1; i <= n; i++)
scanf("%s", ch[i]+1);
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
if (ch[i][j] == 'D')
BFS(++door, i, j);
else if (ch[i][j] == '.') p[i][j] = ++people;
int l = 0, r = people, ans = 666666;
while (l <= r) {
int mid = (l + r) >> 1;
if (check(mid) == people) r = mid-1, ans = mid;
else l = mid+1;
}
if (ans == 666666) puts("impossible");
else printf("%d\n", ans);
return 0;
}
洛谷 P3191 [HNOI2007]紧急疏散EVACUATE(网络最大流)的更多相关文章
- P3191 [HNOI2007]紧急疏散EVACUATE(费用流)
P3191 [HNOI2007]紧急疏散EVACUATE 费用流+卡常优化 我们只关心一个人通过门时的时间,在空地的行走时间可以分层维护 于是根据时间分层,到门的时候再计算代价,即代价$=$层数 每经 ...
- BZOJ1189: [HNOI2007]紧急疏散evacuate 二分+最大流
1189: [HNOI2007]紧急疏散evacuate Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 1132 Solved: 412[Submi ...
- 洛谷P3376【模板】网络最大流 ISAP
这篇博客写得非常好呀. 传送门 于是我是DCOI这一届第一个网络流写ISAP的人了,之后不用再被YKK她们嘲笑我用Dinic了!就是这样! 感觉ISAP是会比Dinic快,只分一次层,然后不能增广了再 ...
- 洛谷P3376 【模板】网络最大流
题目描述 如题,给出一个网络图,以及其源点和汇点,求出其网络最大流. 输入输出格式 输入格式: 第一行包含四个正整数N.M.S.T,分别表示点的个数.有向边的个数.源点序号.汇点序号. 接下来M行每行 ...
- 洛谷 P3376 【模板】网络最大流
题目描述 如题,给出一个网络图,以及其源点和汇点,求出其网络最大流. 输入输出格式 输入格式: 第一行包含四个正整数N.M.S.T,分别表示点的个数.有向边的个数.源点序号.汇点序号. 接下来M行每行 ...
- 洛谷——P3376 【模板】网络最大流
题目描述 如题,给出一个网络图,以及其源点和汇点,求出其网络最大流. 输入输出格式 输入格式: 第一行包含四个正整数N.M.S.T,分别表示点的个数.有向边的个数.源点序号.汇点序号. 接下来M行每行 ...
- 洛谷 P3376【模板】网络最大流
题目描述 如题,给出一个网络图,以及其源点和汇点,求出其网络最大流. 输入输出格式 输入格式: 第一行包含四个正整数N.M.S.T,分别表示点的个数.有向边的个数.源点序号.汇点序号. 接下来M行每行 ...
- 『题解』洛谷P3376 【模板】网络最大流
Problem Portal Portal1:Luogu Description 如题,给出一个网络图,以及其源点和汇点,求出其网络最大流. Input 第一行包含四个正整数\(N,M,S,T\),分 ...
- 洛谷 P3376 【模板】网络最大流 题解
今天学了网络最大流,EK 和 Dinic 主要就是运用搜索求增广路,Dinic 相当于 EK 的优化,先用bfs求每个点的层数,再用dfs寻找并更新那条路径上的值. EK 算法 #include< ...
随机推荐
- php 5.3 以上fpm安装
安装PHP #wget http://cn2.php.net/get/php-5.3.8.tar.gz/from/cn.php.net/mirror #tar -zxvf php-5.3.8.tar. ...
- linux上搭建图片服务器
之前写过一个搭建图片服务器的随笔:https://www.cnblogs.com/xujingyang/p/7163290.html ,现在回头看看,我去,感觉写的好乱,现在再整一个吧.o(╯□╰ ...
- Apache apachectl命令
一.简介 apachectl命令是Apache的Web服务器前端控制工具,用以启动.关闭和重新启动Web服务器进程. 二.语法 http://www.jinbuguo.com/apache/menu2 ...
- 19. AUTO INCREMENT 字段
Auto-increment 会在新记录插入表中时生成一个唯一的数字. AUTO INCREMENT 字段 我们通常希望在每次插入新记录时,自动地创建主键字段的值. 我们可以在表中创建一个 auto- ...
- bzoj5392 [Lydsy1806月赛]路径统计
传送门 分析 我们设sum[x]为小于等于x的点现在有多少联通 于是一个序列合法当且只当sum[R]-sum[L-1]=len且所有点度数不大于2 我们知道如果对于序列[L,R]满足条件则[L+1,R ...
- rpm遇到的坑-与VMP冲突
rpm遇到的坑-与VMP冲突 摘自:https://blog.csdn.net/shijichao2/article/details/78797586 2017年12月13日 22:29:21 阅读数 ...
- javascript总结16:数组array12
1 Array 对象 作用:Array 对象用于在变量中存储多个值. 1.1 数组定义 var ary = new Array();//通过创建对象的方式创建数组 var ary1 = [];// 直 ...
- initWithFrame 和 initWithCoder 区别?
当我们所写的程序里用代码创建控制视图内容,需要调用initWithFrame去初始化 - (id)initWithFrame:(CGRect)frame { if (self =[superinitW ...
- AutoLayout自动布局之VFL语言代码实现(一个神奇的语言)
一.什么是VFL语言?为什么要VFL语言? VFL全称是Visual Format Language,翻译过来是“可视化格式语言” VFL是苹果公司为了简化Autolayout的编码而推出的抽象语言 ...
- Unity3D面试题整合
第一部分 1. 请简述值类型与引用类型的区别答:区别:1.值类型存储在内存栈中,引用类型数据存储在内存堆中,而内存单元中存放的是堆中存放的地址.2.值类型存取快,引用类型存取慢.3.值类型表示实际数据 ...