POJ 3057 Evacuation 二分+最大流
Evacuation
题目连接:
http://poj.org/problem?id=3057
Description
Fires can be disastrous, especially when a fire breaks out in a room that is completely filled with people. Rooms usually have a couple of exits and emergency exits, but with everyone rushing out at the same time, it may take a while for everyone to escape.
You are given the floorplan of a room and must find out how much time it will take for everyone to get out. Rooms consist of obstacles and walls, which are represented on the map by an 'X', empty squares, represented by a '.' and exit doors, which are represented by a 'D'. The boundary of the room consists only of doors and walls, and there are no doors inside the room. The interior of the room contains at least one empty square.
Initially, there is one person on every empty square in the room and these persons should move to a door to exit. They can move one square per second to the North, South, East or West. While evacuating, multiple persons can be on a single square. The doors are narrow, however, and only one person can leave through a door per second.
What is the minimal time necessary to evacuate everybody? A person is evacuated at the moment he or she enters a door square.
Input
The first line of the input contains a single number: the number of test cases to follow. Each test case has the following format:
One line with two integers Y and X, separated by a single space, satisfying 3 <= Y, X <= 12: the size of the room
Y lines with X characters, each character being either 'X', '.', or 'D': a valid description of a room
Output
For every test case in the input, the output should contain a single line with the minimal evacuation time in seconds, if evacuation is possible, or "impossible", if it is not.
Sample Input
3
5 5
XXDXX
X...X
D...X
X...D
XXXXX
5 12
XXXXXXXXXXXX
X..........D
X.XXXXXXXXXX
X..........X
XXXXXXXXXXXX
5 5
XDXXX
X.X.D
XX.XX
D.X.X
XXXDX
Sample Output
3
21
impossible
Hint
题意
一副迷宫图'.'为空格,'D'为门,'#'为墙;
现在每个空格处有一人,且每个时刻每个空格只能站一人;当走到门时为离开房间;求所有人撤离的最短时间,否则impossible;
题解:
二分答案,然后建图跑网络流去check就好了
二分t
S连向每个人,流量为1。每个人向t秒能到达的门流量为1。每个门向T连流量为t的边。然后看是不是满流。
代码
#include<stdio.h>
#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
const int MAXN=100000,MAXM=100000,inf=1e9;
struct Edge
{
int v,c,f,nx;
Edge() {}
Edge(int v,int c,int f,int nx):v(v),c(c),f(f),nx(nx) {}
} E[MAXM];
int G[MAXN],cur[MAXN],pre[MAXN],dis[MAXN],gap[MAXN],N,sz;
void init(int _n)
{
N=_n,sz=0; memset(G,-1,sizeof(G[0])*N);
}
void link(int u,int v,int c)
{
E[sz]=Edge(v,c,0,G[u]); G[u]=sz++;
E[sz]=Edge(u,0,0,G[v]); G[v]=sz++;
}
bool bfs(int S,int T)
{
static int Q[MAXN]; memset(dis,-1,sizeof(dis[0])*N);
dis[S]=0; Q[0]=S;
for (int h=0,t=1,u,v,it;h<t;++h)
{
for (u=Q[h],it=G[u];~it;it=E[it].nx)
{
if (dis[v=E[it].v]==-1&&E[it].c>E[it].f)
{
dis[v]=dis[u]+1; Q[t++]=v;
}
}
}
return dis[T]!=-1;
}
int dfs(int u,int T,int low)
{
if (u==T) return low;
int ret=0,tmp,v;
for (int &it=cur[u];~it&&ret<low;it=E[it].nx)
{
if (dis[v=E[it].v]==dis[u]+1&&E[it].c>E[it].f)
{
if (tmp=dfs(v,T,min(low-ret,E[it].c-E[it].f)))
{
ret+=tmp; E[it].f+=tmp; E[it^1].f-=tmp;
}
}
}
if (!ret) dis[u]=-1; return ret;
}
int dinic(int S,int T)
{
int maxflow=0,tmp;
while (bfs(S,T))
{
memcpy(cur,G,sizeof(G[0])*N);
while (tmp=dfs(S,T,inf)) maxflow+=tmp;
}
return maxflow;
}
char s[23][23];
int dx[4]={1,-1,0,0};
int dy[4]={0,0,1,-1};
int n,m;
int vis[23][23];
int d[405][23][23];
vector<int> doorx,doory;
void doit()
{
for(int i=0;i<doorx.size();i++)
{
int x=doorx[i],y=doory[i];
queue<int>qx,qy;
d[i][x][y]=0;
qx.push(x),qy.push(y);
while(!qx.empty())
{
x=qx.front(),y=qy.front();
qx.pop(),qy.pop();
for(int j=0;j<4;j++)
{
int nx=x+dx[j],ny=y+dy[j];
if(nx<0||nx>=n)continue;
if(ny<0||ny>=m)continue;
if(s[nx][ny]=='D'||s[nx][ny]=='X')continue;
if(d[i][nx][ny]>d[i][x][y]+1)
{
d[i][nx][ny]=d[i][x][y]+1;
qx.push(nx);
qy.push(ny);
}
}
}
}
}
bool check(int t)
{
init(10005);
int S = 9999,T = 10000;
int cnt = 0;
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
{
if(s[i][j]=='.')
link(S,i*m+j,1),cnt++;
if(s[i][j]=='D')
link(i*m+j,T,t);
}
for(int i=0;i<doorx.size();i++)
for(int j=0;j<n;j++)
for(int k=0;k<m;k++)
if(d[i][j][k]<=t&&s[j][k]=='.')
link(j*m+k,doorx[i]*m+doory[i],1);
int cnt2 = dinic(S,T);
if(cnt==cnt2)return true;
return false;
}
int main()
{
int t;scanf("%d",&t);
while(t--){
doorx.clear(),doory.clear();
memset(s,0,sizeof(s));
scanf("%d%d",&n,&m);
for(int i=0;i<n;i++)
scanf("%s",s[i]);
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
if(s[i][j]=='D')
doorx.push_back(i),doory.push_back(j);
for(int i=0;i<=400;i++)
for(int j=0;j<23;j++)
for(int k=0;k<23;k++)
d[i][j][k]=inf;
doit();
int l=0,r=500,ans=-1;
while(l<=r)
{
int mid = (l+r)/2;
if(check(mid))ans=mid,r=mid-1;
else l=mid+1;
}
if(ans==-1)printf("impossible\n");
else printf("%d\n",ans);
}
}
POJ 3057 Evacuation 二分+最大流的更多相关文章
- POJ 3057 Evacuation (二分匹配)
题意:给定一个图,然后有几个门,每个人要出去,但是每个门每个秒只能出去一个,然后问你最少时间才能全部出去. 析:初一看,应该是像搜索,但是怎么保证每个人出去的时候都不冲突呢,毕竟每个门每次只能出一个人 ...
- 【最大匹配+二分答案】POJ 3057 Evacuation
题目大意 POJ链接 有一个\(X×Y\)的房间,X代表墙壁,D是门,.代表人.这个房间着火了,人要跑出去,但是每一个时间点只有一个人可以从门出去. 问最后一个人逃出去的最短时间,如果不能逃出去,输出 ...
- POJ 3057 Evacuation(二分匹配)
分析: 这是一个时间和门的二元组(t,d)和人p匹配的问题,当我们固定d0时,(t,d0)匹配的人数和t具有单调性. t增加看成是多增加了边就行了,所以bfs处理出p到每个d的最短时间,然后把(t,d ...
- POJ 2175 Evacuation Plan (费用流,负环,消圈法,SPFA)
http://poj.org/problem?id=2175 Evacuation Plan Time Limit: 1000MS Memory Limit: 65536K Total Submi ...
- POJ 3057 Evacuation(二分图匹配+BFS)
[题目链接] http://poj.org/problem?id=3057 [题目大意] 给出一个迷宫,D表示门,.表示人,X表示不可通行, 每个门每时间单位只允许一个人通过, 每个人移动一格的为一时 ...
- POJ 3057 Evacuation 题解
题目 Fires can be disastrous, especially when a fire breaks out in a room that is completely filled wi ...
- POJ 2175 Evacuation Plan 费用流 负圈定理
题目给了一个满足最大流的残量网络,判断是否费用最小. 如果残量网络中存在费用负圈,那么不是最优,在这个圈上增广,增广1的流量就行了. 1.SPFA中某个点入队超过n次,说明存在负环,但是这个点不一定在 ...
- TTTTTTTTTTTTT poj 3057 Evacuation 二分图匹配+bfs
题意:见挑战230页 #include <iostream> #include <cstdio> #include <cstring> #include <c ...
- POJ 3057 Evacuation 二分图匹配
每个门每个时间只能出一个人,那就把每个门拆成多个,对应每个时间. 不断增加时间,然后增广,直到最大匹配. //#pragma comment(linker, "/STACK:10240000 ...
随机推荐
- 【POJ2420】A star not a tree?
蒟蒻开始学模拟退火…… 起初一直不肯学,因为毕竟玄学算法…… 哎呀玄学怎么就没用呢?对不对? #include<iostream> #include<cstdio> #incl ...
- leetcode 之LRU Cache(26)
很实际的一道题.定义一个双向链表list,方便插入和删除:定义一个哈希表,方便查找. 具体的,哈希表存放每个结点的key和它对应的结点的地址:访问结点时,如果结点存在,则将其交换到头部,同是更新哈希表 ...
- Linux Python apache的cgi配置
一.找到安装Apache的目录/usr/local/apache2/conf,并对httpd.conf配置文件进行修改 1.加载cgi模块 去掉注释: LoadModule cgid_module m ...
- sql server中字符串无法替换空格的问题
直接上代码: select case when 'workReport'=LTRIM(RTRIM(' workReport ')) then 'trim去空格成功' when 'workReport' ...
- vue利用watch侦听对象具体的属性 ~ 巧用计算属性computed做中间层
有时候需要侦听某个对象具体的属性,可以按下面案例进行: <template> <div> <input type="text" v-model=&qu ...
- AC日记——「SDOI2017」序列计数 LibreOJ 2002
「SDOI2017」序列计数 思路: 矩阵快速幂: 代码: #include <bits/stdc++.h> using namespace std; #define mod 201704 ...
- python 编码处理
# -*- coding: utf-8 -*-import easygui as gimport sysreload(sys)sys.setdefaultencoding('utf-8')
- 错误:Eclipse老是出现 updating error reports database
Eclipse 火星版(Mars)一直出现 updating error reports database. Window--->Preferences--->General---> ...
- python模块之HTMLParser
HTMLParser是python用来解析html的模块.它可以分析出html里面的标签.数据等等,是一种处理html的简便途径. HTMLParser采用的是一种事件驱动的模式,当HTMLParse ...
- 转:Super Awesome Fuzzing, Part One
转:https://labsblog.f-secure.com/2017/06/22/super-awesome-fuzzing-part-one/ An informative guide on u ...