POJ3057 Evacuation 二分图匹配+最短路

题目描述

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

分析

一句话题意:有一个X\(\times\)Y的房间,'X'代表墙壁,‘D’是门,‘.’代表人。这个房间着火了,人要跑出去,但是每一个时间点只有一个人可以从门出去。

问最后一个人逃出去的最短时间,如果不能逃出去,输出impossible。

其实这一道题和题库里外星人那一道题解法大致雷同,只是建边的方式有点不同,我们对比着来说

首先,外星人那一道题就是一个简单的两点之间距离公式求出最短路

但是这一道题肯定是不可以直接用公式的,因为题中会有墙

所以我们要用一个bfs预处理出每一个人到每一扇门的最短路

还有一个更大的不同点就是门的性质

在外星人那一道题中,一个人经过了一扇门后,门就会消失,而这一道题经过一扇门后,门不会消失

所以一扇门可以使用多次,但不能被多个人同时使用

所以我们考虑把一个门拆成若干个小门,每一个门代表一个时刻

我们从0时刻开始枚举,把0时刻每一个人可以到达的门和这个人连一条边

如果0时刻不能匹配成功,我们就把1时刻每一个人可以到达的门和这个人连一条边

以此类推,直到所有的时刻都枚举完毕

那么最大的时刻是多少呢

很显然,一个人如果可以从门里走出去的话,那么他到这个门所花费的时间不会超过\(n\times m\)

其中\(m\)为房间的长度,\(n\)为房间的宽度

我们假设题目中共有\(d\)个门,因为每一个门都要拆分到\(n\times m\)个时间段里,所以我们只要枚举到\(n\times m \times d\)就可以了

如果最后不能匹配成功,人就不能逃生成功

感性地理解一下,就是一个人被一圈墙围在中间

最后,人数为0的情况下要特判,不特判就会输出'impossible'

最后,我们再来讨论一下复杂度的问题

bfs最坏的情况下就是\(12\times12 \times (12 \times12+12 \times24)=62208\)

没什么影响

建边更是可以忽略不计

其实最主要的开销还是在匈牙利上

最坏的情况\(144\)个点,248832条边,总的复杂度为\(35831808\)

但是这样的强度是达不到的,因为你不可能门有144个,人也有144个,所以实际上是可行的

这道题有人可能会想到二分,但是我个人感觉二分是会使时间复杂度升高的

因为不二分的话,只跑一次匈牙利就可以,用二分的话,可能要跑多次

或者是有更好的二分方法我没有想到

代码

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
const int maxn=50005,maxm=15;
char s[maxm][maxm];
int n,m,tot;
int movex[maxm]={1,-1,0,0};
int movey[maxm]={0,0,-1,1};
int dis[maxm][maxm][maxm][maxm];
vector<int> g[maxn];
int match[maxn],vis[maxn];
vector<int> dx,dy,px,py;
int dfs(int xx){
for(int i=0;i<g[xx].size();i++){
int u=g[xx][i];
if(!vis[u]){
vis[u]=1;
if(match[u]==-1 || dfs(match[u])){
match[u]=xx;
return 1;
}
}
}
return 0;
}
void Init(){
memset(dis,0x3f,sizeof(dis));
for(int i=0;i<maxn;i++){
g[i].clear();
}
dx.clear(),dy.clear(),px.clear(),py.clear();
memset(match,-1,sizeof(match));
memset(vis,0,sizeof(vis));
}
void bfs(int xx,int yy){
queue<int> qx,qy;
qx.push(xx),qy.push(yy);
dis[xx][yy][xx][yy]=0;
while(!qx.empty()){
int nx=qx.front();
int ny=qy.front();
qx.pop(),qy.pop();
for(int i=0;i<4;i++){
int mx=movex[i]+nx;
int my=movey[i]+ny;
if(mx>n || mx<=0 || my>m || my<=0 || s[mx][my]!='.') continue;
if(dis[xx][yy][mx][my]>dis[xx][yy][nx][ny]+1){
dis[xx][yy][mx][my]=dis[xx][yy][nx][ny]+1;
qx.push(mx),qy.push(my);
}
}
}
}
void solve(){
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(s[i][j]=='D'){
dx.push_back(i),dy.push_back(j);
bfs(i,j);
}
else if(s[i][j]=='.') px.push_back(i),py.push_back(j);
}
}
int d=dx.size(),p=px.size();
for(int i=0;i<d;i++){
for(int j=0;j<p;j++){
int nows=dis[dx[i]][dy[i]][px[j]][py[j]];
if(nows!=0x3f3f3f3f){
for(int k=nows;k<=tot;k++){
g[k*d+i].push_back(j);
}
}
}
}
if(p==0){
printf("0\n");
return;
}
int ans=0;
for(int i=0;i<tot*d;i++){
memset(vis,0,sizeof(vis));
if(dfs(i)){
if(++ans==p){
printf("%d\n",i/d);
return;
}
}
}
printf("impossible\n");
}
int main(){
int t;
scanf("%d",&t);
while(t--){
Init();
scanf("%d%d",&n,&m);
tot=n*m;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
scanf(" %c",&s[i][j]);
}
}
solve();
}
return 0;
}

POJ3057 Evacuation 二分图匹配+最短路的更多相关文章

  1. TTTTTTTTTTTTT poj 3057 Evacuation 二分图匹配+bfs

    题意:见挑战230页 #include <iostream> #include <cstdio> #include <cstring> #include <c ...

  2. POJ 3057 Evacuation 二分图匹配

    每个门每个时间只能出一个人,那就把每个门拆成多个,对应每个时间. 不断增加时间,然后增广,直到最大匹配. //#pragma comment(linker, "/STACK:10240000 ...

  3. 最短路&生成树&二分图匹配&费用流问题

    最短路 题意理解,建图 https://vjudge.net/problem/UVALive-4128 飞机票+行程建图 https://vjudge.net/problem/UVALive-3561 ...

  4. POJ 3057 Evacuation(二分图匹配+BFS)

    [题目链接] http://poj.org/problem?id=3057 [题目大意] 给出一个迷宫,D表示门,.表示人,X表示不可通行, 每个门每时间单位只允许一个人通过, 每个人移动一格的为一时 ...

  5. BZOJ:[JSOI2009]游戏Game【二分图匹配乱搞】

    题目大意:n*m的棋盘,其中有些区域是禁区,两个人在棋盘上进行博弈,后手选择棋子的初始位置,然后先后手轮流将棋子往上下左右移动,走过的区域不能再走,问能否有一个位置使得后手必胜 Input 输入数据首 ...

  6. 线段树、最短路径、最小生成树、并查集、二分图匹配、最近公共祖先--C++模板

    线段树(区间修改,区间和): #include <cstdio> #include <iostream> #include <cstring> using name ...

  7. UVA 12549 - 二分图匹配

    题意:给定一个Y行X列的网格,网格种有重要位置和障碍物.要求用最少的机器人看守所有重要的位置,每个机器人放在一个格子里,面朝上下左右四个方向之一发出激光直到射到障碍物为止,沿途都是看守范围.机器人不会 ...

  8. POJ 1274 裸二分图匹配

    题意:每头奶牛都只愿意在她们喜欢的那些牛栏中产奶,告诉每头奶牛愿意产奶的牛棚编号,求出最多能分配到的牛栏的数量. 分析:直接二分图匹配: #include<stdio.h> #includ ...

  9. BZOJ1433 ZJOI2009 假期的宿舍 二分图匹配

    1433: [ZJOI2009]假期的宿舍 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 2375  Solved: 1005[Submit][Sta ...

随机推荐

  1. pyhon的浅拷贝与深拷贝

    1.赋值:简单地拷贝对象的引用,两个对象的id相同. 2.浅拷贝:创建一个新的组合对象,这个新对象与原对象共享内存中的子对象. 3.深拷贝:创建一个新的组合对象,同时递归地拷贝所有子对象,新的组合对象 ...

  2. rgb格式颜色与#000000格式颜色的转换

    首先,#000000格式的颜色被成为十六进制颜色码: 6位数分为三组,每两位数一组,依次是红.黄.蓝颜色的强度: 而与此对应的,rgb(39,137,202)依次是十进制的红黄蓝颜色: 因此将rgb格 ...

  3. 是时候拥抱.NET CORE了

    微软和社区已经做了大量艰苦的工作,使.net core成为市场上具有竞争力的框架,帮助开发人员快速开发具有最佳性能和可扩展性的强大应用程序.做的最棒的事情使.net framework开发人员不需要任 ...

  4. windows下Python版本切换使用方法

    由于历史原因,Python有两个大的版本分支,Python2和Python3,又由于一些库只支持某个版本分支,所以需要在电脑上同时安装Python2和Python3,因此如何让两个版本的Python兼 ...

  5. C++值元编程

    --永远不要在OJ上使用值元编程,过于简单的没有优势,能有优势的编译错误. 背景 2019年10月,我在学习算法.有一道作业题,输入规模很小,可以用打表法解决.具体方案有以下三种: 运行时预处理,生成 ...

  6. Spring Cloud Alibaba系列(四)使用gateway作为服务网关

    什么是网关 在微服务架构里,服务的粒度被进一步细分,各个业务服务可以被独立的设计.开发.测试.部署和管理.这时,各个独立部署单元可以用不同的开发测试团队维护,可以使用不同的编程语言和技术平台进行设计, ...

  7. WireShark——IP协议包分析(Ping分析IP协议包)

    互联网协议 IP 是 Internet Protocol 的缩写,中文缩写为“网协”.IP 协议是位于 OSI 模型中第三层的协议,其主要目的就是使得网络间能够互联通信.前面介绍了 ARP 协议, 该 ...

  8. 05、MyBatis 缓存

    1.MyBatis缓存 MyBatis 包含一个非常强大的查询缓存特性,它可以非常方便地配置和定制.缓存可以极大的提升查询效率. 1).一级缓存 public Employee getEmpById( ...

  9. 向强大的SVG迈进

    作者:凹凸曼 - 暖暖 SVG 即 Scalable Vector Graphics 可缩放矢量图形,使用XML格式定义图形. 一.SVG印象 SVG 的应用十分广泛,得益于 SVG 强大的各种特性. ...

  10. Python3-算法-选择排序

    选择排序 选择排序(Selection sort)是一种简单直观的排序算法.它的工作原理是每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完. ...