题目传送门

思路:

  先预处理出每个人到每扇门的时间,用门作为起点进行bfs处理。

  然后二分时间,假设时间为x,将每扇门拆成1到x,x个时间点,表示这扇门有几个时间点是可以出去的。对于一扇门,每个时间点都向后一个时间点建边,表示人在当前时间点到达,可以在下一时间点出去。

  先将s连上所有的空地,流量为1,建立每个空地每个门的对应的时间点流量为1的边,表示这个空地的人会再某一时间点到达这扇门。然后每个门流向t,流量为inf。只要最大流为空地的数量,则代表该时间是可以的,继续向下二分。

#include<bits/stdc++.h>
#define CLR(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
int fx[][]={{,},{,-},{,},{-,}};
int dis[][][],n,m;
char s[][];
int ed[],g[][],cnt,sum,st,t;
const int maxn=;
const int inf=0x3f3f3f3f;
int head[maxn],tot=;
struct edge{
int to,f,Next;
}a[maxn<<];
void addv(int u,int v,int w){
a[++tot].to=v,a[tot].f=w,a[tot].Next=head[u],head[u]=tot;
a[++tot].to=u,a[tot].f=,a[tot].Next=head[v],head[v]=tot;
}
inline void bfs(int id){
queue<int >q;
dis[id][ed[id]/m][ed[id]%m]=;
q.push(ed[id]);
while(!q.empty()){
int u=q.front();
int x=u/m,y=u%m;
q.pop();
for(int i=;i<;i++){
int xx=x+fx[i][],yy=y+fx[i][];
if(xx<||xx>=n||yy<||yy>=m||s[xx][yy]!='.')continue;
if (dis[id][xx][yy]>dis[id][x][y]+)
dis[id][xx][yy]=dis[id][x][y]+,q.push(xx*m+yy); }
}
}
int deep[maxn];
bool vis[maxn];
inline void find(){
CLR(deep,);
queue<int >q;
vis[st]=;
q.push(st);
while(!q.empty()){
int u=q.front();
q.pop();
for(int i=head[u];i!=-;i=a[i].Next)
{
if(a[i].f && !vis[a[i].to]){
q.push(a[i].to);
deep[a[i].to]=deep[u]+;
vis[a[i].to]=;
}
}
}
}
int dfs(int u,int delta){
if(u==t)return delta;
int ret=;
for(int i=head[u];delta&&i!=-;i=a[i].Next){
if(a[i].f&&deep[a[i].to]==deep[u]+){
int dd=dfs(a[i].to,min(a[i].f,delta));
a[i].f-=dd;
a[i^].f+=dd;
delta-=dd;
ret+=dd;
}
}
return ret;
}
inline bool check(int x){
st=,t=maxn-,tot=;
CLR(head,-);
for(int i=;i<=sum;i++)addv(st,i,);
for(int k=;k<=cnt;k++)
for(int i=;i<n;i++)
for(int j=;j<m;j++)
if(s[i][j]=='.'&&dis[k][i][j]<=x)
addv(g[i][j],sum+(k-)*x+dis[k][i][j],); for (int i=; i<=cnt; i++)
for (int j=; j<=x; j++) {
int tmp=(i-)*x+sum;
addv(tmp+j,t,);
if (j<x) addv(tmp+j,tmp+j+,inf);
}
int ret=;
while(){
CLR(vis,);
find();
if(!vis[t]){
return ret==sum;
}
ret+=dfs(st,inf);
}
}
int main(){
cin>>n>>m;
for(int i=;i<n;i++)
{
scanf("%s",s[i]);
}
for(int i=;i<n;i++)
{
for(int j=;j<m;j++)
{
if(s[i][j]=='D'){
ed[++cnt]=i*m+j;
}
if(s[i][j]=='.')g[i][j]=++sum;
}
}
CLR(dis,0x3f);
for(int i=;i<=cnt;i++)
{
bfs(i);
}
int l=,r=n*m,mid;
int ans;
if(!check(r)){
puts("impossible");
return ;
}
while(l<=r){ mid=(l+r)>>;//printf("l:%d r:%d mid:%d\n",l,r,mid);
if(check(mid)){
ans=mid,r=mid-;
// printf("ans:%d\n",ans);
}
else l=mid+;
}
cout<<ans<<endl; }

1189: [HNOI2007]紧急疏散evacuate

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 3825  Solved: 1118
[Submit][Status][Discuss]

Description

发生了火警,所有人员需要紧急疏散!假设每个房间是一个N M的矩形区域。每个格子如果是'.',那么表示这是一
块空地;如果是'X',那么表示这是一面墙,如果是'D',那么表示这是一扇门,人们可以从这儿撤出房间。已知门
一定在房间的边界上,并且边界上不会有空地。最初,每块空地上都有一个人,在疏散的时候,每一秒钟每个人都
可以向上下左右四个方向移动一格,当然他也可以站着不动。疏散开始后,每块空地上就没有人数限制了(也就是
说每块空地可以同时站无数个人)。但是,由于门很窄,每一秒钟只能有一个人移动到门的位置,一旦移动到门的
位置,就表示他已经安全撤离了。现在的问题是:如果希望所有的人安全撤离,最短需要多少时间?或者告知根本
不可能。

Input

第一行是由空格隔开的一对正整数N与M,3<=N <=20,3<=M<=20,
以下N行M列描述一个N M的矩阵。其中的元素可为字符'.'、'X'和'D',且字符间无空格。

Output

只有一个整数K,表示让所有人安全撤离的最短时间,
如果不可能撤离,那么输出'impossible'(不包括引号)。

Sample Input

5 5
XXXXX
X...D
XX.XX
X..XX
XXDXX

Sample Output

3

bzoj 1189 二分+最大流的更多相关文章

  1. bzoj 1189 二分+最大流判定

    首先我们可以二分一个答案时间T,这样就将最优性问题 转化为了判定性问题.下面我们考虑对于已知的T的判定 对于矩阵中所有的空点bfs一次,得出来每个点到门的距离, 然后连接空点和每个能在t时间内到达的门 ...

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

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

  3. bzoj 1305 二分+最大流判定|贪心

    首先我们二分一个答案mid,在判定是否能举办mid次,那么对于每个次我们可以用最大流根据是否满流(流量为n*mid)来判定,对于每个点我们拆成两个点,分别表示这个人要和他喜欢和不喜欢的人一起跳舞,那么 ...

  4. uvalive 3231 Fair Share 公平分配问题 二分+最大流 右边最多流量的结点流量尽量少。

    /** 题目: uvalive 3231 Fair Share 公平分配问题 链接:https://vjudge.net/problem/UVALive-3231 题意:有m个任务,n个处理器,每个任 ...

  5. poj 2391 Ombrophobic Bovines 最短路 二分 最大流 拆点

    题目链接 题意 有\(n\)个牛棚,每个牛棚初始有\(a_i\)头牛,最后能容纳\(b_i\)头牛.有\(m\)条道路,边权为走这段路所需花费的时间.问最少需要多少时间能让所有的牛都有牛棚可待? 思路 ...

  6. HDU3081 Marriage Match II —— 传递闭包 + 二分图最大匹配 or 传递闭包 + 二分 + 最大流

    题目链接:https://vjudge.net/problem/HDU-3081 Marriage Match II Time Limit: 2000/1000 MS (Java/Others)    ...

  7. HDU-3081-Marriage Match II 二分图匹配+并查集 OR 二分+最大流

    二分+最大流: 1 //题目大意:有编号为1~n的女生和1~n的男生配对 2 // 3 //首先输入m组,a,b表示编号为a的女生没有和编号为b的男生吵过架 4 // 5 //然后输入f组,c,d表示 ...

  8. hdu4560 不错的建图,二分最大流

    题意: 我是歌手 Time Limit: 6000/2000 MS (Java/Others) Memory Limit: 65535/32768 K (Java/Others) Total Subm ...

  9. POJ3228二分最大流

    题意:       有n个点,每个点有两个权值,金子数量还有仓库容量,金子可以存在自己的仓库里或者是别的仓库里,仓库和仓库之间有距离,问所有金子都必须存到库里最大距离的最小是多少? 思路:       ...

随机推荐

  1. 283. Move Zeroes把零放在最后面

    [抄题]: Given an array nums, write a function to move all 0's to the end of it while maintaining the r ...

  2. 为什么说Java String 类型的值是不可改变的?

    String对象是不可变的,它的内容是不能改变的.下列代码会改变字符串的内容吗? 1 2 String s = "Java"; s = "HTML"; 答案是不 ...

  3. win32多线程(三) 死锁

    任何时候当一段代码需要两个(或更多)资源时,都有潜在性的死锁. void SwapLists(List *list1, List *list2) { List *tmp_list; EnterCrit ...

  4. js-修改url中某个指定的参数的值

    /* * url 目标url * arg 需要替换的参数名称 * arg_val 替换后的参数的值 * return url 参数替换后的url */ function changeURLArg(ur ...

  5. ibatis和hibernate

    ibatis:sql需要自己写hibernate:sql自动生成上面是最大的区别,下面是一些细节.选择Hibernate还是iBATIS都有它的道理:Hibernate的特点:Hibernate功能强 ...

  6. delphi xe6 for android 自带控件LocationSensor优先使用GPS定位的方法

    delphi xe6 for android LocationSensor控件默认是优先使用网络定位,对定位精度要求高的应用我们可以修改原码直接指定GPS定位. 修改方法: 将C:\Program F ...

  7. 倍增求lca(模板)

    定义LCA,最近公共祖先,是指一棵树上两个节点的深度最大的公共祖先.也可以理解为两个节点之间的路径上深度最小的点.我们这里用了倍增的方法求了LCA.我们的基本的思路就是,用dfs遍历求出所有点的深度. ...

  8. vs2015+opencv3.3.1 +Eigen 3.3.4 c++ 实现 泊松图像编辑(无缝融合)

    #define EIGEN_USE_MKL_ALL #define EIGEN_VECTORIZE_SSE4_2 #include <iostream> #include "co ...

  9. BST_insert

    #include <stdio.h> /* printf, scanf, NULL */ #include <stdlib.h> /* malloc, free */ stru ...

  10. kali 插耳机没声音

    打开终端,然后输入命令:下载pulseaudio音量控制软件: apt install pavucontrol 然后终端输入指令:pavucontrol打开软件,发现在输出设备中有两个输出设备:一个N ...