二分答案,网络流判断

将每个门拆点,每个人连向每个门的dis~当前解

然后跑最大流,如果等于人数,即为可行解

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<map>
#define pa pair<int,int>
#define N 405
#define inf 0x7fffffff
using namespace std;
int n,m,p,per=0,door=0,S,T;
pa pos[N];
char s[25],a[25][25];
map<pa,int> pp,dd;
int h,t,xx[N],yy[N];
int dis[N][N];
bool bo[N][N];
int e=2,head[50005];
struct edge{
int u,v,f,next;
}ed[8000005];
void add(int u,int v,int f){
ed[e].u=u; ed[e].v=v; ed[e].f=f;
ed[e].next=head[u]; head[u]=e++;
ed[e].u=v; ed[e].v=u; ed[e].f=0;
ed[e].next=head[v]; head[v]=e++;
}
void bfs(int x,int y){
memset(bo,0,sizeof bo);
h=t=1; xx[1]=x; yy[1]=y;
int now=dd[pa(x,y)];
while(h<=t){
int tx=xx[h],ty=yy[h++];
if(tx-1>0&&a[tx-1][ty]=='.'&&!bo[tx-1][ty]){
dis[pp[pa(tx-1,ty)]][now]=(tx==x&&ty==y?1:dis[pp[pa(tx,ty)]][now]+1);
xx[++t]=tx-1; yy[t]=ty; bo[tx-1][ty]=1;
}
if(tx+1<=n&&a[tx+1][ty]=='.'&&!bo[tx+1][ty]){
dis[pp[pa(tx+1,ty)]][now]=(tx==x&&ty==y?1:dis[pp[pa(tx,ty)]][now]+1);
xx[++t]=tx+1; yy[t]=ty; bo[tx+1][ty]=1;
}
if(ty-1>0&&a[tx][ty-1]=='.'&&!bo[tx][ty-1]){
dis[pp[pa(tx,ty-1)]][now]=(tx==x&&ty==y?1:dis[pp[pa(tx,ty)]][now]+1);
xx[++t]=tx; yy[t]=ty-1; bo[tx][ty-1]=1;
}
if(ty+1<=m&&a[tx][ty+1]=='.'&&!bo[tx][ty+1]){
dis[pp[pa(tx,ty+1)]][now]=(tx==x&&ty==y?1:dis[pp[pa(tx,ty)]][now]+1);
xx[++t]=tx; yy[t]=ty+1; bo[tx][ty+1]=1;
}
}
}
int dep[50005],q[50005];
bool bfs(){
memset(dep,0,sizeof dep);
dep[S]=1; h=t=1; q[1]=S;
while(h<=t){
int x=q[h++];
for(int i=head[x];i;i=ed[i].next){
if(ed[i].f&&!dep[ed[i].v]){
dep[ed[i].v]=dep[x]+1;
q[++t]=ed[i].v;
if(ed[i].v==T) return 1;
}
}
}
return 0;
}
int dfs(int x,int f){
if(x==T||f==0) return f;
int ans=0;
for(int i=head[x];i;i=ed[i].next){
if(ed[i].f&&dep[ed[i].v]==dep[x]+1){
int nxt=dfs(ed[i].v,min(f,ed[i].f));
ed[i].f-=nxt; ed[i^1].f+=nxt;
ans+=nxt; f-=nxt;
if(f==0) break;
}
}
if(ans==0)dep[x]=-1;
return ans;
}
int dinic(){
int ans=0;
while(bfs())
ans+=dfs(S,inf);
return ans;
}
bool work(int x){
e=2; memset(head,0,sizeof head);
S=per+x*door+1;T=S+1;
for(int i=1;i<=per;i++)
for(int j=1;j<=door;j++)
for(int k=dis[i][j]==0?inf:dis[i][j];k<=x;k++)
add(i,per+(k-1)*door+j,1);
for(int i=1;i<=per;i++) add(S,i,1);
for(int i=per+1;i<=per+x*door;i++) add(i,T,1);
if(dinic()==per) return 1;
return 0;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%s",s+1);
for(int j=1;j<=m;j++){
a[i][j]=s[j];
pos[++p]=make_pair(i,j);
if(a[i][j]=='.')
pp[pos[p]]=++per;
if(a[i][j]=='D')
dd[pos[p]]=++door;
}
}
for(int i=1;i<=m;i++){
if(a[1][i]=='D')bfs(1,i);
if(a[n][i]=='D')bfs(n,i);
}
for(int i=1;i<=n;i++){
if(a[i][1]=='D')bfs(i,1);
if(a[i][m]=='D')bfs(i,m);
}
for(int i=1;i<=per;i++){
bool booo=1;
for(int j=1;j<=door;j++)
if(dis[i][j]) {booo=0;break;}
if(booo==1){
printf("impossible\n");
return 0;
}
}
int l=1,r=324,mid;
while(l+1<r){
mid=(l+r)/2;
if(work(mid)) r=mid;
else l=mid;
}
if(work(l)) printf("%d\n",l);
else printf("%d\n",r);
return 0;
}

bzoj 1189 紧急疏散 网络流的更多相关文章

  1. BZOJ 1189 紧急疏散(二分+最大流)

    求出所有人撤离的最短时间.由于每扇门只能通过一次,所以不能简单用bfs来搞. 显然答案是有单调性的,考虑二分,问题变成了判断时间x所有人能不能撤离. 考虑最大流.对于每扇门,每个时间通过的人数最多为1 ...

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

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

  3. BZOJ 1189: [HNOI2007]紧急疏散evacuate( BFS + 二分答案 + 匈牙利 )

    我们可以BFS出每个出口到每个人的最短距离, 然后二分答案, 假设当前答案为m, 把一个出口拆成m个表示m个时间, 点u到出口v的距离为d, 那么u->v的[d, m]所有点连边, 然后跑匈牙利 ...

  4. BZOJ 1189 【HNOI2007】 紧急疏散evacuate

    题目链接:紧急疏散 这薄脊题我代码不知不觉就写长了…… 这道题二分答案显然,然后用最大流\(check\)即可.设当前二分的答案为\(x\),那么把每扇门拆成\(x\)个点,第\(i\)个代表在第\( ...

  5. BZOJ 1189 [HNOI2007]紧急疏散evacuate

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

  6. 【BZOJ 1189】[HNOI2007]紧急疏散evacuate

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

  7. AC日记——[HNOI2007]紧急疏散evacuate bzoj 1189

    [HNOI2007]紧急疏散evacuate 思路: 处理每个人到门的最短路: 然后二分答案: s向人连边流量1: 人向门拆分后的点连边流量1(拆成400,前一个点连当前点流量INF): 然后门向t连 ...

  8. bzoj 1189: [HNOI2007]紧急疏散evacuate 分层图最大流_拆点_二分

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

  9. BZOJ 1189 二分匹配 || 最大流

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

随机推荐

  1. nginx日志中添加请求的response日志

    换个新公司,做一些新鲜的事情,经过一天的琢磨,终于成功添加response日志 在nginx的日志中添加接口response的日志 由于此功能在nginx内置的功能中没有,需要安装第三方模块ngx_l ...

  2. Python进程与线程

    进程与线程:*进程: 进程是系统中程序执行和资源分配的基本单元, 每个进程都有自己的数据段(存储数据).代码段(存储代码).堆栈段(对象和变量). # 全局变量等资源在多个进程中不能          ...

  3. 拖拽模块move1

    刚开的博客,想着写点什么,以前写过拖拽函数,后来又学习了模块化,于是一直想把之前写的拖拽函数封成一个独立的模块,方便以后调用,说干就干,下面码代码... <script> var move ...

  4. Linux基础命令归纳大全

    Linux发行版本:基于linux内核提供桌面环境及办公套件的操作系统 (Linux内核只有一个)   1. 启动终端的快捷键: ctr + alt + t 2. 终端字体放大: ctr+shift+ ...

  5. win8系统下,python 2.7安装xlrd,xlutils和xlwt的方法

    一.先到python的官网上下载压缩包 二.将压缩包解压 三.将打开cmd,进入到解压文件所在的位置 四.键入 python setup.py install

  6. 用户注册登录系统 V2.0

    # 准备空列表 users = [] # 准备当前在线用户 online_user = {} while True: # 打印系统提示 print("欢迎使用 用户注册登录系统V2.0&qu ...

  7. TCP的流量控制和拥塞处理

    1. 利用滑动窗口实现流量控制 如果发送方把数据发送得过快,接收方可能会来不及接收,这就会造成数据的丢失.所谓流量控制就是让发送方的发送速率不要太快,要让接收方来得及接收.    利用滑动窗口机制可以 ...

  8. Linux环境安装配置JDK

    本文安装环境为Ubuntu14 64位,jdk版本为jdk1.6.0_38,安装文件名为jdk-6u38-linux-x64.bin(根据系统不同,下载不同的安装文件) 下载地址:http://www ...

  9. QPropertyAnimation实现图形,控件的旋转和位移动画,尤其是旋转

    QPropertyAnimation可以简单方便的实现对象的旋转和移动的动画效果. 1. 移动 Pixmap *item = new Pixmap(kineticPix); QPropertyAnim ...

  10. 【转】Fundebug上线微信小游戏错误监控!支持自动截屏!

    摘要: Fundebug竭诚为你的小游戏保驾护航. 想必大家都玩过"跳一跳"吧?刷排行榜的感觉是不是很好啊!还有"知乎答题王"呢,在智力上碾压老铁简直太棒了! ...