bzoj 1189: [HNOI2007]紧急疏散evacuate 分层图最大流_拆点_二分
Description
Input
题解:
一眼分层图最短路,按时间将每个点拆开.
然而,空间时爆炸的,节点层数过多.
不过,我们有一个非常好的性质:由于任意时刻每个空格上不限人数,人们可以直接走最短路径走向每扇门.
这样,就不必对每一个空地拆点,只需将门按照时间拆开并连边即可.
处理最短路径我们选择 Floyd.
Code:
#include<bits/stdc++.h>
#define setIO(s) freopen(s".in","r",stdin)
#define maxn 100000
#define inf 100000
using namespace std;
namespace Dinic{
struct Edge{
int from,to,cap;
Edge(int a=0,int b=0,int c=0):from(a),to(b),cap(c){}
};
queue<int>Q;
vector<Edge>edges;
vector<int>G[maxn];
void add(int u,int v,int c){
edges.push_back(Edge(u,v,c));
edges.push_back(Edge(v,u,0));
int m=edges.size();
G[u].push_back(m-2);
G[v].push_back(m-1);
}
int S,T,vis[maxn],d[maxn],current[maxn];
int BFS(){
memset(vis,0,sizeof(vis));
vis[S]=1,d[S]=0; Q.push(S);
while(!Q.empty()){
int u=Q.front();Q.pop();
for(int sz=G[u].size(),i=0;i<sz;++i){
Edge r = edges[G[u][i]];
if(!vis[r.to] && r.cap>0) {
vis[r.to]=1,d[r.to]=d[u]+1;
Q.push(r.to);
}
}
}
return vis[T];
}
int dfs(int x,int cur){
if(x==T) return cur;
int flow=0,f;
for(int sz=G[x].size(),i=current[x];i<sz;++i){
current[x]=i;
Edge r = edges[G[x][i]];
if(d[r.to]==d[x]+1&&r.cap>0) {
if(f=dfs(r.to,min(cur,r.cap))) {
flow+=f,cur-=f;
edges[G[x][i]].cap-=f,edges[G[x][i]^1].cap+=f;
}
}
if(cur==0) break;
}
return flow;
}
int maxflow(){
int flow=0;
while(BFS()){
memset(current,0,sizeof(current));
flow+=dfs(S,inf);
}
return flow;
}
void re(){
S=T=0;
for(int i=0;i<maxn;++i) G[i].clear();
edges.clear();
}
};
char str[500];
int gr[500][500],d[500][500],ck[500][500];
#define idx(i,j) ((i-1)*m+j)
#define nex (id+10)
vector<int>gate,G[maxn];
int mapp[500][300],n,m,sum;
bool check(int t){
int id=0;
Dinic::re();
Dinic::S=0,Dinic::T=5000;
for(int sz=gate.size(),i=0;i<sz;++i) {
mapp[gate[i]][0]=++id; Dinic::add(id,5000,1);
for(int j=1;j<=t;++j) { mapp[gate[i]][j]=++id; Dinic::add(id-1,id,inf),Dinic::add(id,5000,1); }
}
int tot=n*m;
for(int i=1;i<=tot;++i) {
for(int sz=G[i].size(),j=0;j<sz;++j) if(d[i][G[i][j]]<=t) Dinic::add(i+nex,mapp[G[i][j]][d[i][G[i][j]]],1);
if(G[i].size()) Dinic::add(0,i+nex,1);
}
return (Dinic::maxflow()==sum);
}
int main(){
//setIO("input");
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i){
scanf("%s",str+1);
for(int j=1;j<=m;++j) {
if(str[j]=='.') gr[i][j]=0,++sum;
if(str[j]=='X') gr[i][j]=1;
if(str[j]=='D') { gr[i][j]=2; gate.push_back(idx(i,j)); }
}
}
for(int i=1;i<=n*m;++i)
for(int j=1;j<=n*m;++j) d[i][j]=inf;
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j) {
if(i-1>=1&&gr[i-1][j]!=1) d[idx(i,j)][idx(i-1,j)]=ck[idx(i,j)][idx(i-1,j)]=1;
if(i+1<=n&&gr[i+1][j]!=1) d[idx(i,j)][idx(i+1,j)]=ck[idx(i,j)][idx(i+1,j)]=1;
if(j+1<=m&&gr[i][j+1]!=1) d[idx(i,j)][idx(i,j+1)]=ck[idx(i,j)][idx(i,j+1)]=1;
if(j-1>=1&&gr[i][j-1]!=1) d[idx(i,j)][idx(i,j-1)]=ck[idx(i,j)][idx(i,j-1)]=1;
}
int tot=n*m;
for(int i=1;i<=tot;++i) ck[i][i]=1,d[i][i]=0;
for(int k=1;k<=tot;++k)
for(int i=1;i<=tot;++i)
for(int j=1;j<=tot;++j) if(ck[i][k]&&ck[k][j]) ck[i][j]=1;
for(int k=1;k<=tot;++k)
for(int i=1;i<=tot;++i)
for(int j=1;j<=tot;++j) if(ck[i][j]) d[i][j]=min(d[i][j],d[i][k]+d[k][j]);
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j)
if(gr[i][j]==0){
bool flag=0;
for(int sz=gate.size(),t=0;t<sz;++t){
if(ck[idx(i,j)][gate[t]]) G[idx(i,j)].push_back(gate[t]);
flag=1;
}
if(!flag) { printf("impossible"); return 0; }
}
int l=1,r=400,ans,mid;
while(l<=r){
mid=(l+r)>>1;
if(check(mid)) ans=mid,r=mid-1;
else l=mid+1;
}
printf("%d",ans);
return 0;
}
bzoj 1189: [HNOI2007]紧急疏散evacuate 分层图最大流_拆点_二分的更多相关文章
- 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 ...
- BZOJ 1189 [HNOI2007]紧急疏散evacuate
Description 发生了火警,所有人员需要紧急疏散!假设每个房间是一个N M的矩形区域.每个格子如果是'.',那么表示这是一块空地:如果是'X',那么表示这是一面墙,如果是'D',那么表示这是一 ...
- 【BZOJ】1189: [HNOI2007]紧急疏散evacuate(二分+bfs+网络流)
http://www.lydsy.com/JudgeOnline/problem.php?id=1189 表示完全不会QAQ.... 于是膜拜题解orz 二分时间........... 于是转换成判定 ...
- 1189: [HNOI2007]紧急疏散evacuate - BZOJ
Description 发生了火警,所有人员需要紧急疏散!假设每个房间是一个N M的矩形区域.每个格子如果是'.',那么表示这是一块空地:如果是'X',那么表示这是一面墙,如果是'D',那么表示这是一 ...
- 1189: [HNOI2007]紧急疏散evacuate
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 3831 Solved: 1119[Submit][Status][Discuss] Descript ...
- 洛谷 P3191 [HNOI2007]紧急疏散EVACUATE(网络最大流)
题解 二分答案+Dinic最大流 二分答案\(mid\) 把门拆成\(mid\)个时间点的门 相邻时间的门连一条\(inf\)的边 预处理出每个门到每个人的最短时间 为\(dis[k][i][j]\) ...
- bzoj千题计划132:bzoj1189: [HNOI2007]紧急疏散evacuate
http://www.lydsy.com/JudgeOnline/problem.php?id=1189 二分答案 源点向人连边,流量为1 门拆为mid个点,同一个门的第j个点向第j+1个点连边,流量 ...
- Bzoj1189 [HNOI2007]紧急疏散evacuate
1189: [HNOI2007]紧急疏散evacuate Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 2293 Solved: 715 Descr ...
随机推荐
- poj 3041 最小点覆盖=最大匹配
#include<stdio.h> #include<string.h> #define N 510 int map[N][N],n,mark[N],link[N]; in ...
- 编写自己的starter项目(battcn-starter-swagger)
自定义 starter 项目,方便其他地方调用,类似 spring.datasource.url 这种,本次以自己封装的 battcn-starter-swagger 为案例 创建一个Maven工程 ...
- POJ 2831
次小生成树.求出两点间最短路径的最大权值,再把要加入的边与之比较即可. #include <iostream> #include <cstdio> #include <c ...
- AC自己主动机模板(数组实现版)
BY 九野 做了一道题,用我的那种写法华丽丽的超时了.,无奈学一学数组实现的 #include<stdio.h> #include<string.h> #include< ...
- 齐头并进完成任务——Java多线程(一)
多线程(Multithread)指的是在单个进程中同时运行多个不同的线程,执行不同的任务.多线程意味着一个程序的多行语句块并发执行. 一.实现多线程 1.通过继承Thread类实现多线程. Threa ...
- C C++每个头文件的功能说
C/C++每个头文件的功能说明 传统 C++ #include <assert.h> //设定插入点 #include <ctype.h> //字符处理 #include &l ...
- php建立简单的用户留言系统
php建立简单的用户留言系统 样例 addMsg.php--添加留言页面 doAction.php--响应添加留言页面 . viewMsg.php--显示留言页面 目录结构 addMsg.php--添 ...
- 辨异 —— Java 中的抽象类和接口
接口优于抽象类.-- <Effective Java>(Item 18) 0. 语法区别 抽象类允许给出某些方法的实现,接口不允许: 为了实现由抽象类定义的类型(type),类必须成为抽象 ...
- reportlab使用示例:文字和图片
Python的reportlab专门将数据使用生成PDF中的图形和文档功能, 下载ReportLab https://pypi.python.org/simple/reportlab/ http:// ...
- js例子
1.子菜单下拉 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www ...