luogu P3191 [HNOI2007]紧急疏散EVACUATE
qwq这题好大力
首先可以预处理出每个人到每个门前面那个格子的最早时间,然后答案如果比最小答案大的话也是合法的,所以可以二分最终答案.检查\(mid\)是否合法就考虑每个人要去哪个门才会合法,所以可以网络流:从原点向每个人连容量为1的边;对所有门建\(mid\)个点,每个点都向汇点连容量为\(1\)的边,并且向下一个时间的点连\(inf\)边,表示每个门每个时刻最多走1个人,同时剩下的人可以在后面的时刻出去;每个人向每个门在最早能到的时间对应的点连1边,然后\(dinic\)判断是否流量等于人数即可
ps:本人网络流板子极丑,慎看
#include<bits/stdc++.h>
#define LL long long
#define il inline
#define re register
#define db double
#define eps (1e-5)
using namespace std;
const int N=22,M=N*N*N*N*2,P=N*N*N,inf=2333333;
il LL rd()
{
LL x=0,w=1;char ch=0;
while(ch<'0'||ch>'9') {if(ch=='-') w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
return x*w;
}
int to[M],nt[M],w[M],hd[P],tot=1;
il void add(int x,int y,int z)
{
++tot,to[tot]=y,nt[tot]=hd[x],w[tot]=z,hd[x]=tot;
++tot,to[tot]=x,nt[tot]=hd[y],w[tot]=0,hd[y]=tot;
}
int lv[P],ss,tt;
bool iqu[P];
bool bfs()
{
memset(lv,63,sizeof(lv));
memset(iqu,0,sizeof(iqu));
lv[ss]=1,iqu[ss]=true;
queue<int> q;
q.push(ss);
while(!q.empty())
{
int x=q.front();
q.pop();
for(int i=hd[x];i;i=nt[i])
{
int y=to[i],c=w[i];
if(c>0&&lv[y]>lv[x]+1)
{
lv[y]=lv[x]+1;
if(!iqu[y]) q.push(y);
iqu[y]=true;
}
}
iqu[x]=false;
}
return lv[tt]<lv[tt+1];
}
int dfs(int x,int nw)
{
if(x==tt) return nw;
int sm=0;
for(int i=hd[x];i&&nw;i=nt[i])
{
int y=to[i],c=w[i];
if(c>0&&lv[y]==lv[x]+1)
{
int dt=dfs(y,min(nw,c));
w[i]-=dt,w[i^1]+=dt;
sm+=dt,nw-=dt;
}
}
return sm;
}
int mvx[4]={0,1,0,-1},mvy[4]={1,0,-1,0};
int n,m,a[N][N],pp[N*N][2],tp,dr[N*N][2],td,di[N][N],ed[N*N][N*N];
bool v[N][N];
il bool check(int mid)
{
tt=tp+(mid+1)*td+3;
memset(hd,0,sizeof(hd)),tot=1;
for(int j=1;j<=td;j++)
for(int i=0;i<mid;i++) add(j+tp+i*td,tt,1),add(j+tp+i*td,j+tp+(i+1)*td,inf);
for(int i=1;i<=tp;i++)
{
add(ss,i,1);
for(int j=1;j<=td;j++) if(ed[i][j]<mid) add(i,j+tp+ed[i][j]*td,1);
}
int sm=0;
while(bfs())
sm+=dfs(ss,inf);
return sm==tp;
}
int main()
{
n=rd(),m=rd();
char cc[N];
for(int i=1;i<=n;i++)
{
scanf("%s",cc+1);
for(int j=1;j<=m;j++)
{
if(cc[j]=='.') pp[++tp][0]=i,pp[tp][1]=j,a[i][j]=1;
else if(cc[j]=='D') dr[++td][0]=i,dr[td][1]=j,a[i][j]=1;
}
}
memset(ed,63,sizeof(ed));
queue<int> q1,q2;
for(int h=1;h<=tp;h++)
{
int sx=pp[h][0],sy=pp[h][1];
memset(di,63,sizeof(di));
di[sx][sy]=0,v[sx][sy]=true;
q1.push(sx),q2.push(sy);
while(!q1.empty())
{
int x=q1.front(),y=q2.front();
q1.pop(),q2.pop();
for(int i=0;i<4;i++)
{
int xx=x+mvx[i],yy=y+mvy[i];
if(a[xx][yy]&&di[xx][yy]>di[x][y]+1)
{
di[xx][yy]=di[x][y]+1;
if(!v[xx][yy]) q1.push(xx),q2.push(yy);
}
}
v[x][y]=false;
}
for(int o=1;o<=td;o++) ed[h][o]=di[dr[o][0]][dr[o][1]]-1;
}
int l=1,r=n*m,ans=-1;
while(l<=r)
{
int mid=(l+r)>>1;
if(check(mid)) ans=mid,r=mid-1;
else l=mid+1;
}
ans>0?printf("%d\n",ans):puts("impossible");
return 0;
}
luogu P3191 [HNOI2007]紧急疏散EVACUATE的更多相关文章
- P3191 [HNOI2007]紧急疏散EVACUATE(费用流)
P3191 [HNOI2007]紧急疏散EVACUATE 费用流+卡常优化 我们只关心一个人通过门时的时间,在空地的行走时间可以分层维护 于是根据时间分层,到门的时候再计算代价,即代价$=$层数 每经 ...
- 洛谷 P3191 [HNOI2007]紧急疏散EVACUATE(网络最大流)
题解 二分答案+Dinic最大流 二分答案\(mid\) 把门拆成\(mid\)个时间点的门 相邻时间的门连一条\(inf\)的边 预处理出每个门到每个人的最短时间 为\(dis[k][i][j]\) ...
- P3191 [HNOI2007]紧急疏散EVACUATE
传送门 这一题很容易想到网络流 一开始傻逼地模拟整个图每一个时间的情况,显然会爆炸 发现我们只要考虑起点到门之间的距离,不用每一步只走一格 所以直接 $BFS$ 预处理距离然后二分答案,网络流判断即可 ...
- 题解 P3191 [HNOI2007]紧急疏散EVACUATE
题解 本篇题解做法为BFS+二分+最大流 二分需要撤离的时间,也就是答案(这算是一个比较套路的了) 重点在于建模(设时间为 \(tim\)): 我们将每个门拆点,拆成 \(tim\) 个,每个点向汇点 ...
- Bzoj1189 [HNOI2007]紧急疏散evacuate
1189: [HNOI2007]紧急疏散evacuate Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 2293 Solved: 715 Descr ...
- 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]所有点连边, 然后跑匈牙利 ...
- [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个点连边,流量 ...
随机推荐
- rabbitmq代码配置
package com.qukoucai.test; import com.rabbitmq.client.AMQP;import com.rabbitmq.client.AMQP.BasicProp ...
- Bootstrap面板
前面的话 面板(Panels)是Bootstrap框架新增的一个组件,某些时候可能需要将某些 DOM 内容放到一个盒子里.对于这种情况,可以使用面板组件.本文将详细介绍Bootstrap面板 基础面板 ...
- MyBatis:一对一关联查询
MyBatis从入门到放弃三:一对一关联查询 前言 简单来说在mybatis.xml中实现关联查询实在是有些麻烦,正是因为起框架本质是实现orm的半自动化. 那么mybatis实现一对一的关联查询则是 ...
- AGC005F Many Easy Problems(NTT)
先只考虑求某个f(k).考虑转换为计算每条边的贡献,也即该边被所选连通块包含的方案数.再考虑转换为计算每条边不被包含的方案数.这仅当所选点都在该边的同一侧.于是可得f(k)=C(n,k)+ΣC(n,k ...
- day12-13 文件操作b模式
为什么需要用到二进制的形式?我们默认的r w a 其实是rt wt at 即txt模式如果是图片,视频,音频,是无法用txt打开的,只能用b模式处理 b 模式是以字节形式打开 f = open(&qu ...
- Partition Numbers的计算
partition numbers的定义 A000041 就是将正整数n分为k(\(1\le k\le n)\)个正整数相加,即\(n=a_1+a_2+...+a_k\)且\(a_1\le a_2\l ...
- 自学Linux Shell8.2-linux逻辑卷LVM管理
点击返回 自学Linux命令行与Shell脚本之路 8.2-linux逻辑卷LVM管理 Linux逻辑卷管理器软件包用来通过将另外一个硬盘上的分区加入已有文件系统,动态地添加存储空间. 1. 逻辑卷L ...
- JOISC 2017 自然公园
吐槽 YMD的课件是真的毒,YYB的也很毒. 题目链接 LOJ sol 我是一个一个Subtask做的... Subtask 1 \(O(n^2)\)枚举每两个点有没有边即可. Subtask 2 链 ...
- py3+urllib+re,爬虫下载捧腹网图片
实现原理及思路请参考我的另外几篇爬虫实践博客 py3+urllib+bs4+反爬,20+行代码教你爬取豆瓣妹子图:http://www.cnblogs.com/UncleYong/p/6892688. ...
- luogu4185 [USACO18JAN]MooTube (并查集)
类似于NOI2018d1t1的离线做法,把询问存下来,排个序,然后倒着给并查集加边,每次询问并查集联通块大小 #include<bits/stdc++.h> #define ll long ...