题目链接

sb错误调了3hour+。。

bfs预处理出每个\(.\)到每个\(D\)的最短距离。

二分时间\(t\),把每个\(D\)拆成\(t\)个点,这\(t\)个点两两连边,流量\(INF\)表示\(t\)个时刻都可以从这个\(D\)出。

然后枚举所有\(.\),再枚举所有\(D\),如果距离\(dis\)小于\(t\),就从这个\(.\)向这个\(D\)的第\(dis\)个点连一条流量为\(1\)的边,表示从这个时刻开始这个\(.\)可以从这个\(D\)出。

然后求最大流,如果等于\(.\)的个数,说明此\(t\)可行,二分一下即可。

#include <cstdio>
#include <queue>
#include <cstdlib>
#include <cstring>
#define INF 2147483647
using 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 <int> q;
queue <point> 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;
}

【洛谷 P3191】 [HNOI2007]紧急疏散EVACUATE(二分答案,最大流)的更多相关文章

  1. 洛谷 P3191 [HNOI2007]紧急疏散EVACUATE(网络最大流)

    题解 二分答案+Dinic最大流 二分答案\(mid\) 把门拆成\(mid\)个时间点的门 相邻时间的门连一条\(inf\)的边 预处理出每个门到每个人的最短时间 为\(dis[k][i][j]\) ...

  2. BZOJ1189: [HNOI2007]紧急疏散evacuate(二分答案,最大流)

    Description 发生了火警,所有人员需要紧急疏散!假设每个房间是一个N M的矩形区域.每个格子如果是'.',那么表示这是一 块空地:如果是'X',那么表示这是一面墙,如果是'D',那么表示这是 ...

  3. P3191 [HNOI2007]紧急疏散EVACUATE(费用流)

    P3191 [HNOI2007]紧急疏散EVACUATE 费用流+卡常优化 我们只关心一个人通过门时的时间,在空地的行走时间可以分层维护 于是根据时间分层,到门的时候再计算代价,即代价$=$层数 每经 ...

  4. BZOJ1189: [HNOI2007]紧急疏散evacuate 二分+最大流

    1189: [HNOI2007]紧急疏散evacuate Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1132  Solved: 412[Submi ...

  5. bzoj 1189 [HNOI2007]紧急疏散evacuate 二分+网络流

    [HNOI2007]紧急疏散evacuate Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 3626  Solved: 1059[Submit][St ...

  6. [CodePlus 2017 11月赛&洛谷P4058]木材 题解(二分答案)

    [CodePlus 2017 11月赛&洛谷P4058]木材 Description 有 n棵树,初始时每棵树的高度为 Hi ,第 i棵树每月都会长高 Ai.现在有个木料长度总量为 S的订单, ...

  7. 洛谷P4589 [TJOI2018]智力竞赛(二分答案 二分图匹配)

    题意 题目链接 给出一个带权有向图,选出n + 1n+1条链,问能否全部点覆盖,如果不能,问不能覆盖的点权最小值最大是多少 Sol TJOI怎么净出板子题 二分答案之后直接二分图匹配check一下. ...

  8. 洛谷 P1824 进击的奶牛 【二分答案】(求最大的最小值)

    题目链接:https://www.luogu.org/problemnew/show/P1824 题目描述 Farmer John建造了一个有N(2<=N<=100,000)个隔间的牛棚, ...

  9. 洛谷P3964 [TJOI2013]松鼠聚会 [二分答案,前缀和,切比雪夫距离]

    题目传送门 松鼠聚会 题目描述 草原上住着一群小松鼠,每个小松鼠都有一个家.时间长了,大家觉得应该聚一聚.但是草原非常大,松鼠们都很头疼应该在谁家聚会才最合理. 每个小松鼠的家可以用一个点x,y表示, ...

  10. 洛谷P3576 [POI2014]MRO-Ant colony [二分答案,树形DP]

    题目传送门 MRO-Ant colony 题目描述 The ants are scavenging an abandoned ant hill in search of food. The ant h ...

随机推荐

  1. web.py 中文模版报错

    1. 作为模板的html文件,必须是utf-8编码; 2. html文件内容中的charset必须为utf-8,也就是必须包含 <meta http-equiv="Content-Ty ...

  2. 九度-题目1026:又一版 A+B

    http://ac.jobdu.com/problem.php?pid=1026 题目描述: 输入两个不超过整型定义的非负10进制整数A和B(<=231-1),输出A+B的m (1 < m ...

  3. utuntu下安装pip&pip3

    在utuntu下建议不要使用apt-get install 安装pip,会出现很多问题. 建议使用如下方式安装: wget https://bootstrap.pypa.io/get-pip.py - ...

  4. 只要实现了annotation这个接口就是注解 同理:只要实现了某个接口就是该类型的实现类

    只要实现了annotation这个接口就是注解  同理:只要实现了某个接口就是该类型的实现类

  5. Java Machine Learning Tools & Libraries--转载

    原文地址:http://www.demnag.com/b/java-machine-learning-tools-libraries-cm570/?ref=dzone This is a list o ...

  6. P1054 等价表达式

    题目描述 明明进了中学之后,学到了代数表达式.有一天,他碰到一个很麻烦的选择题.这个题目的题干中首先给出了一个代数表达式,然后列出了若干选项,每个选项也是一个代数表达式,题目的要求是判断选项中哪些代数 ...

  7. ORM框架SQLAlchemy使用学习

    参考源:http://blog.csdn.net/fgf00/article/details/52949973 一.ORM介绍 如果写程序用pymysql和程序交互,那是不是要写原生sql语句.如果进 ...

  8. jQuery绑定事件

    1.事件绑定的方式 事件 DOM:三种绑定方式 jQuery: #前面几种内部调用的全是on $('.c1').click() $('.c1').blur() $('.c1').aaaaa() $(' ...

  9. ans menu list

    ans menu list 1. 系统配置 a) 基本设置 i. NTP ii. 配置模式 iii. 主机信息 b) 高可用性 i. 节点 ii. 路由监视器 iii. 故障转移接口群 c) 设备标识 ...

  10. javascript的解析顺序

    一.javascript的解析顺序 我们大家所理解的代码的执行顺序都是从上到下的,但是实际上确不是这样的.我们看一下下面的代码. 1 alert(a);2 var a = 1;如果执行顺序是从上到下的 ...