Luogu3191 HNOI2007 紧急疏散 二分答案、最大流
题意:自己去看
考虑二分答案。$BFS$预处理出每一个人到每一扇门的最短时间,设二分的值为$mid$,那么把门拆成$mid$个点,每一个点代表第$1,2,...,mid$秒时的状态。$i-1$时刻的门向$i$时刻的门连一条流量为$INF$的边,表示有无限多的人可以在门口等待。每一个门拆出来的$mid$个点向汇点连流量为$1$的边表示逃出的一个人;源点向每一个人连一条流量为$1$的边,每一个人对应的点向每一扇门的最早到达时刻对应的点连一条流量为$1$的边,最后计算最大流是否等于人数即可。
#include<bits/stdc++.h>
#define MAXN 7010
#define XX now.x + dir[i][0]
#define YY now.y + dir[i][1]
#define INF 0x7fffffff
using namespace std; struct Edge{
int end , upEd , flow;
}Ed[MAXN << ];
struct node{
int x , y , flo;
}now;
const int dir[][] = {,,,-,,,-,};
int head[MAXN] , flo[MAXN] , cur[MAXN] , cntEd , cntBlock , N , M , cntDoor , dis[][] , mid;
map < pair < int , int > , int > door;
char c[][];
bool vis[][] , be[MAXN];
queue < int > q1;
queue < node > q2; void bfs(int x , int y){
cntBlock++;
memset(dis[cntBlock] , 0x3f , sizeof(dis[cntBlock]));
q2.push((node){x , y , });
memset(vis , , sizeof(vis));
vis[x][y] = ;
while(!q2.empty()){
now = q2.front();
q2.pop();
for(int i = ; i < ; i++)
if(c[XX][YY] != 'X' && !vis[XX][YY]){
vis[XX][YY] = ;
if(c[XX][YY] == 'D')
dis[cntBlock][door.find(make_pair(XX , YY))->second] = now.flo + ;
else
q2.push((node){XX , YY , now.flo + });
}
}
} bool div(){
while(!q1.empty())
q1.pop();
memset(be , , sizeof(be));
q1.push();
be[] = flo[] = ;
while(!q1.empty()){
int t = q1.front();
q1.pop();
for(int i = head[t] ; i ; i = Ed[i].upEd){
if(!be[Ed[i].end] && Ed[i].flow){
flo[Ed[i].end] = flo[t] + ;
be[Ed[i].end] = ;
if(Ed[i].end == cntBlock + cntDoor * mid + ){
memcpy(cur , head , sizeof(head));
return ;
}
q1.push(Ed[i].end);
}
}
}
return ;
} bool dinic(int now){
if(now == cntBlock + cntDoor * mid + )
return ;
for(int &i = cur[now] ; i ; i = Ed[i].upEd)
if(flo[Ed[i].end] == flo[now] + && Ed[i].flow)
if(dinic(Ed[i].end)){
Ed[i].flow--;
Ed[i ^ ].flow++;
return ;
}
return ;
} inline void addEd(int a , int b , int c){
Ed[++cntEd].end = b;
Ed[cntEd].flow = c;
Ed[cntEd].upEd = head[a];
head[a] = cntEd;
} bool check(){
memset(head , , sizeof(head));
cntEd = ;
int T = cntDoor * mid + cntBlock + ;
for(int i = ; i < cntDoor ; i++)
for(int j = ; j < mid ; j++){
addEd(mid * i + j + cntBlock , mid * i + j + cntBlock + , INF);
addEd(mid * i + j + cntBlock + , mid * i + j + cntBlock , );
}
for(int i = ; i < cntDoor ; i++)
for(int j = ; j <= mid ; j++){
addEd(mid * i + j + cntBlock , T , );
addEd(T , mid * i + j + cntBlock , );
}
int cnt = ;
for(int i = ; i < N ; i++)
for(int j = ; j < M ; j++)
if(c[i][j] == '.'){
cnt++;
for(int k = ; k <= cntDoor ; k++)
if(dis[cnt][k] <= mid){
addEd(cnt , mid * (k - ) + dis[cnt][k] + cntBlock , );
addEd(mid * (k - ) + dis[cnt][k] + cntBlock , cnt , );
}
addEd( , cnt , );
addEd(cnt , , );
}
int ans = ;
while(div())
while(dinic())
ans++;
return ans == cntBlock;
} int main(){
cin >> N >> M;
for(int i = ; i <= N ; i++)
for(int j = ; j <= M ; j++){
cin >> c[i][j];
if(c[i][j] == 'D')
door.insert(make_pair(make_pair(i , j) , ++cntDoor));
}
for(int i = ; i < N ; i++)
for(int j = ; j < M ; j++)
if(c[i][j] == '.')
bfs(i , j);
int L = , R = N * M;
while(L < R){
mid = L + R >> ;
check() ? R = mid : L = mid + ;
}
if(R == N * M)
cout << "impossible";
else
cout << R;
return ;
}
Luogu3191 HNOI2007 紧急疏散 二分答案、最大流的更多相关文章
- BZOJ 1570: [JSOI2008]Blue Mary的旅行( 二分答案 + 最大流 )
二分答案, 然后对于答案m, 把地点分成m层, 对于边(u, v), 第x层的u -> 第x+1层的v 连边. 然后第x层的u -> 第x+1层的u连边(+oo), S->第一层的1 ...
- BZOJ 1738: [Usaco2005 mar]Ombrophobic Bovines 发抖的牛( floyd + 二分答案 + 最大流 )
一道水题WA了这么多次真是.... 统考终于完 ( 挂 ) 了...可以好好写题了... 先floyd跑出各个点的最短路 , 然后二分答案 m , 再建图. 每个 farm 拆成一个 cow 点和一个 ...
- BZOJ 1305 CQOI2009 dance跳舞 二分答案+最大流
题目大意:给定n个男生和n个女生,一些互相喜欢而一些不.举行几次舞会,每次舞会要配成n对.不能有同样的组合出现.每一个人仅仅能与不喜欢的人跳k次舞,求最多举行几次舞会 将一个人拆成两个点.点1向点2连 ...
- HDU3081(KB11-N 二分答案+最大流)
Marriage Match II Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others ...
- BZOJ2547 CTSC2002玩具兵(最短路径+二分答案+最大流)
先不考虑只有一个显得有些特殊的天兵. 可以发现超能力的作用实质上是使兵更换职业.每一个兵到达某个位置最少需要更换职业的次数是彼此独立的,因为如果需要某两人互换职业可以使他们各自以当前职业到达需要到的地 ...
- Gym - 101908G 二分答案+最大流
After the end of the truck drivers' strike, you and the rest of Nlogônia logistics specialists now h ...
- 「LuoguP3191」 [HNOI2007]紧急疏散EVACUATE(最大流
Description 发生了火警,所有人员需要紧急疏散!假设每个房间是一个N M的矩形区域.每个格子如果是’.’,那么表示这是一块空地:如果是’X’,那么表示这是一面墙,如果是’D’,那么表示这是一 ...
- 紫书 习题 11-10 UVa 12264 (二分答案+最大流)
书上写的是UVa 12011, 实际上是 12264 参考了https://blog.csdn.net/xl2015190026/article/details/51902823 这道题就是求出一种最 ...
- luoguP1401 城市(二分答案+最大流)
题意 N(2<=n<=200)个城市,M(1<=m<=40000)条无向边,你要找T(1<=T<=200)条从城市1到城市N的路,使得最长的边的长度最小,边不能重复 ...
随机推荐
- 函数节流scroll,兼容火狐滚轮事件
//函数节流 var wheelTimeout; var wheelFun = function (func) { if (wheelTimeout) { return; } func(); whee ...
- Kotlin入门(16)容器的遍历方式
Kotlin号称全面兼容Java,于是乎Java的容器类仍可在Kotlin中正常使用,包括大家熟悉的队列ArrayList.映射HashMap等等.不过Kotlin作为一门全新的语言,肯定还是要有自己 ...
- springboot 学习之路 22 (读取自定义文件)
springboot读取自定义的properties文件: package com.huhy.demo.properties; import lombok.Data; import org.sprin ...
- 导入另一个 Git库到现有的Git库并保留提交记录
在要合并到的目标git仓库,执行 "git pull 远程分支地址/本地git仓库根目录"
- 进程管理-PV操作
1.临界资源:诸进程需要互斥方式对其进行共享的资源. 2.临界区:每个进程中访问临界资源的那段代码. 3.信号量:一种特殊的变量.
- Column Index out of range, 2 > 1 列索引的范围,2 > 1。
Column Index out of range, 2 > 1 列索引的范围,2 > 1.这个问题是进行数据库查询的时候出现的. 因为查询sql语句时 只查询了 name 然后whil ...
- SMBus与I2C的差别
The I²C bus and the SMBus are popular 2-wire buses that areessentially compatible with each other. - ...
- 【PAT】B1080 MOOC期终成绩(25 分)
还是c++好用,三部分输入直接用相同的方法, 用map映射保存学生在结构体数组中的下标. 结构体保存学生信息,其中期末成绩直接初始化为-1, 注意四舍五入 此题还算简单 #include<ios ...
- Windows Server 2012 RS 配置IIS8.0+发布网站
一.配置iis 8.0 IIS 8.0 是 windows server 2012 自带的服务器管理系统.相比之前版本,IIS 8.0 安装和操作都更加简单,界面也很简洁,安装也很迅速. 1. 进入w ...
- orcale 把日期当做查询条件
根据日期查询范围 精确到天 select * from table where to_char( time,'yyyy mm dd ' ) <= '2000 01 01' select * ...