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 ...
随机推荐
- LeetCode 20 Generate Parentheses
Given n pairs of parentheses, write a function to generate all combinations of well-formed parenthes ...
- linux内核网络接收数据流程图【转】
转自:http://blog.chinaunix.net/uid-23069658-id-3141409.html 4.3 数据接收流程图 各层主要函数以及位置功能说明: 1)s ...
- Linux 删除带有特殊字符的文件
Linux 删除带有特殊字符的文件 http://www.cnblogs.com/tester-hehehe/p/5715128.html
- 用Python写个自动ssh登录远程服务器的小工具
很多时候我们喜欢在自己电脑的终端直接ssh连接Linux服务器,而不喜欢使用那些有UI界面的工具区连接我们的服务器.可是在终端使用ssh我们每次都需要输入账号和密码,这也是一个烦恼,所以我们可以简单的 ...
- 查看mysql的版本和端口号
查看版本:select version(); 查看端口号:show global variables like 'port';
- Network Embedding
网络表示 网络表示学习(DeepWalk,LINE,node2vec,SDNE) https://blog.csdn.net/u013527419/article/details/76017528 网 ...
- python_day1学习笔记
一.Python 2.7.x 和 3.x 版本的区别小结 print函数 1.python2 import platform print ‘Python’, platform.python_versi ...
- poj 2593&&poj2479(最大两子段和)
Max Sequence Time Limit: 3000MS Memory Limit: 65536K Total Submissions: 16850 Accepted: 7054 Des ...
- 我感觉prometheus这种日志收集模式不错
思想可以,可推可拉,可自己写接入点...还有报警... 按官方文档试一下安装 https://prometheus.io/docs/introduction/getting_started/
- Go语言建立一个最简单的服务端点
handlers/handlers.go package handlers import ( "encoding/json" "net/http" ) func ...