题目

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.

输入格式

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

输出格式

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.

样例输入

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

样例输出

3
21
impossible

题解

这道题要用二分图的最大匹配来做

对于每一扇门,同一秒只能让一个人通过,那我们就为每一扇门在每一秒建一个节点。

对于每一个人,假设他最快可以在 \(t\) 的时间到达门 \(i\),那就把\(t\)到最大时间(图的大小) 这些节点建边连到人 \(j\)。

如果在这个图上跑二分匹配,匹配的边 <\(t\)时的门\(i\), 人\(j\)> 就代表人 \(j\) 会在时间 \(t\) 时从门 \(i\) 逃脱。

找最短时间, 不断地枚举点,从该点找增广路。当从时间小的门的点开始枚举,这就代表时间小的门会优先匹配。我们只需看看枚举到哪个时间的门的时候,总匹配数等于人的数量,也是就所有人都被匹配到时,程序就可以结束了。答案就是此时的时间。

实现的时候, 可以从每个门做一次 bfs,来找各个人到各个点所需的时间

代码

#include <cstdio>
#include <queue>
#include <cstring>
using namespace std;
int V, X, Y, dxy[4][2] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
char map[13][13];
vector<int> G[50010], dx, dy, px, py;
int match[50005], dist[13][13][13][13];
bool vis[50005];
void add(int u, int v) { G[u].push_back(v), G[v].push_back(u); }
bool find(int v) {
vis[v] = 1;
for (int i = 0; i < G[v].size(); i++) {
int u = G[v][i];
if (match[u] == -1 || !vis[match[u]] && find(match[u]))
return match[v] = u, match[u] = v, true;
}
return false;
}
void bfs(int x, int y, int d[13][13]) {
queue<int> qx, qy;
d[x][y] = 0;
qx.push(x), qy.push(y);
while (!qx.empty()) {
x = qx.front(), qx.pop();
y = qy.front(), qy.pop();
for (int k = 0; k < 4; k++) {
int nx = x + dxy[k][0], ny = y + dxy[k][1];
if (0 <= nx && nx < X && 0 <= ny && ny < Y && map[nx][ny] == '.' && d[nx][ny] < 0) {
d[nx][ny] = d[x][y] + 1;
qx.push(nx), qy.push(ny);
}
}
}
}
int main() {
int t;
scanf("%d", &t);
while (t--) {
scanf("%d%d", &X, &Y);
for (int i = 0; i < X; i++) scanf("%s", map[i]);
int n = X * Y;
dx.clear(), dy.clear(), px.clear(), py.clear();
memset(dist, -1, sizeof(dist));
for (int x = 0; x < X; x++)
for (int y = 0; y < Y; y++) {
if (map[x][y] == 'D') {
dx.push_back(x), dy.push_back(y), bfs(x, y, dist[x][y]);
} else if (map[x][y] == '.')
px.push_back(x), py.push_back(y);
}
int d = dx.size(), p = px.size();
V = X * Y * d + p;
for (int v = 0; v < V; ++v) G[v].clear();
for (int i = 0; i < d; i++)
for (int j = 0; j < p; j++)
if (dist[dx[i]][dy[i]][px[j]][py[j]] >= 0)
for (int k = dist[dx[i]][dy[i]][px[j]][py[j]]; k <= n; k++)
add((k - 1) * d + i, n * d + j);
if (p == 0) {
puts("0");
continue;
}
int res = 0, flag = 1;
memset(match, -1, sizeof(match));
for (int v = 0; v < n * d; v++) {
memset(vis, 0, sizeof(vis));
if (find(v) && ++res == p) {
printf("%d\n", v / d + 1);
flag = 0;
break;
}
}
if(flag)puts("impossible");
}
}

POJ 3057 Evacuation 题解的更多相关文章

  1. POJ 3057 Evacuation 二分+最大流

    Evacuation 题目连接: http://poj.org/problem?id=3057 Description Fires can be disastrous, especially when ...

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

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

  3. 【最大匹配+二分答案】POJ 3057 Evacuation

    题目大意 POJ链接 有一个\(X×Y\)的房间,X代表墙壁,D是门,.代表人.这个房间着火了,人要跑出去,但是每一个时间点只有一个人可以从门出去. 问最后一个人逃出去的最短时间,如果不能逃出去,输出 ...

  4. POJ 3057 Evacuation 二分图匹配

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

  5. POJ 3057 Evacuation (二分匹配)

    题意:给定一个图,然后有几个门,每个人要出去,但是每个门每个秒只能出去一个,然后问你最少时间才能全部出去. 析:初一看,应该是像搜索,但是怎么保证每个人出去的时候都不冲突呢,毕竟每个门每次只能出一个人 ...

  6. [poj] 3057 Evacuation

    原题 题目大意 墙壁"X",空区域(都是人)".", 门"D". 人向门移动通过时视为逃脱,门每秒能出去一个人,人可以上下左右移动,墙阻止移 ...

  7. POJ 3057 Evacuation(二分匹配)

    分析: 这是一个时间和门的二元组(t,d)和人p匹配的问题,当我们固定d0时,(t,d0)匹配的人数和t具有单调性. t增加看成是多增加了边就行了,所以bfs处理出p到每个d的最短时间,然后把(t,d ...

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

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

  9. POJ 3057 网络流 Evacuation

    题意: 有一个n×m的房间,四周每个格子要么是墙要么是门.中间部分是墙或者人. 现在所有人要从房间逃出去,每个人的速度为1,也就是每个单位时间只能向上下左右四个方向走一格. 多个人可以站在同一个格子上 ...

随机推荐

  1. Linux 递归acl权限和默认acl权限

    递归acl权限 递归acl指给父目录设定acl时,所有的子文件和子目录都拥有相同的acl权限 setfacl -m u:boduo:rx -R /project/ 默认acl权限 默认acl权限的作用 ...

  2. 【Spring注解驱动开发】聊聊Spring注解驱动开发那些事儿!

    写在前面 今天,面了一个工作5年的小伙伴,面试结果不理想啊!也不是我说,工作5年了,问多线程的知识:就只知道继承Thread类和实现Runnable接口!问Java集合,竟然说HashMap是线程安全 ...

  3. 05.Django-form表单与请求的生命周期

    Django中请求的生命周期 HTTP请求及服务端响应中传输的所有数据都是字符串 步骤 用户在浏览器中输入url时,浏览器会生成请求头和请求体发给服务器 url经过wsgi和中间件,到达路由映射表,在 ...

  4. 2.3 sqlmap目录及结构

    2.3 sqlmap目录及结构Tips:此篇文章主要参考了<sqlmap从入门到精通>这本书中的相关具体细节,由于这本书作者完成的时间大概在2017年作用,所以我根据书中提到的信息再根据目 ...

  5. ASP.NET Core通过Nacos SDK读取阿里云ACM

    背景 前段时间,cranelee 在Github上给老黄提了个issues, 问到了如何用Nacos的SDK访问阿里云ACM. https://github.com/catcherwong/nacos ...

  6. java类的加载顺序和实例化顺序(Demo程序)

    一.main函数中实例化对象 父类 package com.learn; public class Father { //静态变量 public static int num_1 = 1; //静态代 ...

  7. go mod 与单元测试

    目录 go mod 创建mod 默认模块名 指定模块名 引入其他模块 go 单元测试 创建源文件和测试文件 calc.go calc_test.go 运行测试用例 go mod 为解决go模块间的相互 ...

  8. 别让HR再质问我:我费劲招的人,你用缓存问废了,不能简单点?

    概念 缓存穿透 在高并发下,查询一个不存在的值时,缓存不会被命中,导致大量请求直接落到数据库上,如活动系统里面查询一个不存在的活动. 缓存击穿 在高并发下,对一个特定的值进行查询,但是这个时候缓存正好 ...

  9. ubuntu12.04 dnw2 fl2440 配置

    1.安装libusb-dev sudo apt-get install libusb-dev 2.dnw2编译配置 源码如下,将其保存为dnw2.c 编译命令 gcc dnw2.c -o dnw2 - ...

  10. Cron表达式,springboot定时任务

    详细请看这篇博客 参考:https://blog.csdn.net/belonghuang157405/article/details/83410197 Cron表达式是一个字符串,字符串以5或6个空 ...