【二分答案】【最大流】[HNOI2007]紧急疏散EVACUATE
[HNOI2007]紧急疏散EVACUATE
题目描述
发生了火警,所有人员需要紧急疏散!假设每个房间是一个N M的矩形区域。每个格子如果是'.',那么表示这是一块空地;如果是'X',那么表示这是一面墙,如果是'D',那么表示这是一扇门,人们可以从这儿撤出房间。已知门一定在房间的边界上,并且边界上不会有空地。最初,每块空地上都有一个人,在疏散的时候,每一秒钟每个人都可以向上下左右四个方向移动一格,当然他也可以站着不动。疏散开始后,每块空地上就没有人数限制了(也就是说每块空地可以同时站无数个人)。但是,由于门很窄,每一秒钟只能有一个人移动到门的位置,一旦移动到门的位置,就表示他已经安全撤离了。现在的问题是:如果希望所有的人安全撤离,最短需要多少时间?或者告知根本不可能。
输入输出格式
输入格式:
输入文件第一行是由空格隔开的一对正整数N与M,3<=N <=20,3<=M<=20,以下N行M列描述一个N M的矩阵。其中的元素可为字符'.'、'X'和'D',且字符间无空格。
输出格式:
只有一个整数K,表示让所有人安全撤离的最短时间,如果不可能撤离,那么输出'impossible'(不包括引号)。
输入输出样例
5 5
XXXXX
X...D
XX.XX
X..XX
XXDXX
3 试题分析:创建超级源S,超级汇T
方便起见,先对于每一块空地BFS求出它到每个能到达的门的距离
然后二分答案,建图。
S连到每一个节点,容量为1的边。代表每个位置上有一个人。
简单粗暴的建图方法就是直接对于每个点将其每个时刻的点都建出来,会T一个点。
考虑优化,发现我们不用管每个时刻这个门的状态是什么,而是只用关心最后从这个门出去多少个。
所以我们的建图方法如下:
①S连接到每一块空地容量为1
②每一块空地连接到其在二分答案时间内可以到的门,容量为1
③将每一个门连向T,容量为X(二分的时间)
代码:
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<queue>
#include<algorithm>
using namespace std;
inline int read(){
int x=0,f=1;char c=getchar();
for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
for(;isdigit(c);c=getchar()) x=x*10+c-'0';
return x*f;
}
#define LL long long
const int MAXN = 500001;
const int MAXN2 = 1000001;
const int INF = 9999999; int N,M;
int Root[MAXN2+1],Next[MAXN2+1],Node[MAXN+1],C[MAXN2+1];
int cnt;
char Map[21][21]; void insert(int u,int v,int w){
C[cnt]=w; Node[cnt]=v;
Next[cnt]=Root[u]; Root[u]=cnt++;
return ;
}
struct data{
int x,y,tm;
};
bool vis[21][21];
int dis[21][21][21][21];
int dist[5][2]={{0,-1},{0,1},{1,0},{-1,0}};
int ans; int S,T,KT;
void BFST(){
data t;
for(int i=1;i<=N;i++){
for(int j=1;j<=M;j++){
if(Map[i][j]=='.'){
++KT;
queue<data> Que;
t.x=i; t.y=j; t.tm=0;
Que.push(t);
memset(vis,0,sizeof(vis)); vis[i][j]=true;
while(!Que.empty()){
data k=Que.front(); Que.pop();
if(Map[k.x][k.y]=='D'){
dis[i][j][k.x][k.y]=k.tm;
continue;
}
for(int l=0;l<4;l++){
int xx=k.x+dist[l][0];
int yy=k.y+dist[l][1];
if(xx<1||yy<1||xx>N||yy>M||Map[xx][yy]=='X'||vis[xx][yy]) continue;
t.x=xx; t.y=yy; t.tm=k.tm+1;
vis[xx][yy]=true;
Que.push(t);
}
}
}
}
}
return ;
}
int D[MAXN+1];
bool BFS(){
queue<int> Que; Que.push(S);
memset(D,0,sizeof(D)); D[S]=1;
while(!Que.empty()){
int k=Que.front(); Que.pop();
for(int x=Root[k];x>-1;x=Next[x]){
int v=Node[x];
if(C[x]>0&&!D[v]){
D[v]=D[k]+1;
if(v==T) return true;
Que.push(v);
}
}
}
return false;
}
int cur[MAXN+1];
int DFS(int k,int t){
if(k==T) return t;
int res=0;
for(int x=cur[k];x>-1;x=Next[x]){
int v=Node[x];
if(C[x]>0&&D[v]==D[k]+1){
int tmp=DFS(v,min(C[x],t));
if(!tmp) continue;
C[x]-=tmp; t-=tmp; C[x^1]+=tmp; res+=tmp;
if(!t) return res;
}
cur[k]=x;
}
if(!res) D[k]=-1;
return res;
}
bool check(int K){
cnt=0;
for(int i=0;i<=MAXN;i++) Root[i]=-1;
memset(Next,0,sizeof(Next)); S=0,T=500000;
memset(C,0,sizeof(C)); memset(Node,0,sizeof(Node));
for(int i=1;i<=N;i++){
for(int j=1;j<=M;j++){
if(Map[i][j]=='.'){
insert(S,(i-1)*M+j,1);
insert((i-1)*M+j,S,0);
for(int l1=1;l1<=N;l1++){
for(int l2=1;l2<=M;l2++){
if(Map[l1][l2]=='D'&&dis[i][j][l1][l2]&&dis[i][j][l1][l2]<=K){
insert((i-1)*M+j,(l1-1)*M+l2,1);
insert((l1-1)*M+l2,(i-1)*M+j,0);
}
}
}
}
else if(Map[i][j]=='D'){
insert((i-1)*M+j,T,K);
insert(T,(i-1)*M+j,0);
}
}
}
int ans=0; --cnt;
while(BFS()){
for(int i=0;i<=N*M;i++) cur[i]=Root[i];
ans+=DFS(S,INF);
}
return ans>=KT;
} int main(){
N=read(),M=read();
for(int i=1;i<=N;i++){
for(int j=1;j<=M;j++)
cin>>Map[i][j];
}
BFST();
int l=0,r=400;
while(l<=r){
int mid=(l+r)>>1;
if(check(mid)) ans=mid,r=mid-1;
else l=mid+1;
}
if(ans) printf("%d\n",ans);
else puts("impossible");
}
【二分答案】【最大流】[HNOI2007]紧急疏散EVACUATE的更多相关文章
- BZOJ1189: [HNOI2007]紧急疏散evacuate 二分+最大流
1189: [HNOI2007]紧急疏散evacuate Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 1132 Solved: 412[Submi ...
- BZOJ 1189: [HNOI2007]紧急疏散evacuate( BFS + 二分答案 + 匈牙利 )
我们可以BFS出每个出口到每个人的最短距离, 然后二分答案, 假设当前答案为m, 把一个出口拆成m个表示m个时间, 点u到出口v的距离为d, 那么u->v的[d, m]所有点连边, 然后跑匈牙利 ...
- bzoj 1189 [HNOI2007]紧急疏散evacuate 二分+网络流
[HNOI2007]紧急疏散evacuate Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 3626 Solved: 1059[Submit][St ...
- P3191 [HNOI2007]紧急疏散EVACUATE(费用流)
P3191 [HNOI2007]紧急疏散EVACUATE 费用流+卡常优化 我们只关心一个人通过门时的时间,在空地的行走时间可以分层维护 于是根据时间分层,到门的时候再计算代价,即代价$=$层数 每经 ...
- Bzoj1189 [HNOI2007]紧急疏散evacuate
1189: [HNOI2007]紧急疏散evacuate Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 2293 Solved: 715 Descr ...
- [HNOI2007]紧急疏散EVACUATE (湖南2007年省选)
[HNOI2007]紧急疏散EVACUATE 题目描述 发生了火警,所有人员需要紧急疏散!假设每个房间是一个N M的矩形区域.每个格子如果是'.',那么表示这是一块空地:如果是'X',那么表示这是一面 ...
- bzoj千题计划132:bzoj1189: [HNOI2007]紧急疏散evacuate
http://www.lydsy.com/JudgeOnline/problem.php?id=1189 二分答案 源点向人连边,流量为1 门拆为mid个点,同一个门的第j个点向第j+1个点连边,流量 ...
- AC日记——[HNOI2007]紧急疏散evacuate bzoj 1189
[HNOI2007]紧急疏散evacuate 思路: 处理每个人到门的最短路: 然后二分答案: s向人连边流量1: 人向门拆分后的点连边流量1(拆成400,前一个点连当前点流量INF): 然后门向t连 ...
- 【BZOJ1189】[HNOI2007]紧急疏散evacuate 动态加边网络流
[BZOJ1189][HNOI2007]紧急疏散evacuate Description 发生了火警,所有人员需要紧急疏散!假设每个房间是一个N M的矩形区域.每个格子如果是'.',那么表示这是一块空 ...
随机推荐
- 表单元素(form、文本、按钮、选择)
表单元素 一.form form代表表单,功能:用于申明表单,定义采集数据的范围,也就是<form>和</form>里面包含的数据将被提交到服务器或者电子邮件里.<for ...
- 【转】IOS版本自定义字体步骤
本文转载自:http://quick.cocoachina.com/wiki/doku.php?id=ios%E7%89%88%E6%9C%AC%E4%BD%BF%E7%94%A8%E8%87%AA% ...
- bASE--Risk
//参考base-4.0.2.jar public class Risk implements Serializable //规则名public String ruleName; //规则包名publ ...
- linux安装lamp
github https://github.com/zblogcn/zblogphp Installation If your server system: CentOS yum -y install ...
- Python模块学习 - psutil
psutil模块介绍 psutil是一个开源切跨平台的库,其提供了便利的函数用来获取才做系统的信息,比如CPU,内存,磁盘,网络等.此外,psutil还可以用来进行进程管理,包括判断进程是否存在.获取 ...
- 增大dma的分配
前言 项目中需要通过驱动与fpga通讯,获取fpga往内存里写的数据.因为数据量比较大,需要驱动分配600多M的内存给fpga来写数据,且因为是与fpga通讯,需要连续的内存,还得是uncached的 ...
- jquery - 实例1
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="text2.aspx.cs& ...
- django渲染模板时跟vue使用的{{ }}冲突解决方法
var vm = new Vue({ el: '#app', // 分割符: 修改vue中显示数据的语法, 防止与django冲突 delimiters: ['[[', ']]'], data: { ...
- MyBatis3-与Spring 4集成
继续使用前一篇的例子http://www.cnblogs.com/EasonJim/p/7052368.html,实际项目中,通常会用Spring来管理DataSource等.充分利用Spring基于 ...
- sql server中字符串无法替换空格的问题
直接上代码: select case when 'workReport'=LTRIM(RTRIM(' workReport ')) then 'trim去空格成功' when 'workReport' ...