传送门:http://poj.org/problem?id=3057
题意:
有X*Y个点,每个点可能是'X'(墙壁),'.'(人),'D'(门),周围一圈只可能是'X','D'。每个门在同一时刻只能出去一个人,每个人每个时刻只能走一格,问全部人撤离最少需要多少时间。
思路:
首先bfs预处理每个门到每个人的最短距离,如果有人无法到达所有门,那么直接输出"impossible"。
之后将每个人作为一个点。将每个时刻的每个门作为一个点,若该时刻这扇门与这个人的距离小于等于时刻,则两者连边。利用二分图匹配,当匹配数等于人数的时候,该时刻就是答案。
AC代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cstdlib>
#include<utility>
#include<algorithm>
#include<utility>
#include<queue>
#include<vector>
#include<set>
#include<stack>
#include<cmath>
#include<map>
#include<ctime>
#include<functional>
#define P pair<int,int>
#define ll long long
#define ull unsigned long long
#define lson id*2,l,mid
#define rson id*2+1,mid+1,r
#define ls id*2
#define rs id*2+1
#define Mod(a,b) a<b?a:a%b+b
using namespace std;
const int maxn = 100010;
const ll M = 1e9 + 7;
const ll INF = 1e9;
const int N = 10000;
const double e = 10e-6;
const int dx[4] = { 0,0,1,-1 }, dy[4] = { 1,-1,0,0 };
int V;
vector<int> G[N];
int match[N];
bool used[N];
void addEdge(int u, int v)
{
G[u].push_back(v); G[v].push_back(u);
}
void init()
{
for (int i = 0; i < N; i++)
G[i].clear();
}
bool dfs(int v)
{
used[v] = true;
for (int i = 0; i < G[v].size(); i++) {
int u = G[v][i], w = match[u];
if (w < 0 || !used[w] && dfs(w)) {
match[v] = u; match[u] = v;
return true;
}
}
return false;
}
int n, m;
char maze[20][20];
vector<P> d, p;
int id[20][20];
int dis[200][200];
struct node
{
P p;
int dis;
};
void bfs(int u)
{
queue<node> que; que.push(node{ d[u], 0 });
while (!que.empty()) {
node v = que.front(); que.pop();
for (int i = 0; i < 4; i++) {
int x = v.p.first + dx[i], y = v.p.second + dy[i];
if (x < 0 || x >= n || y < 0 || y >= m)continue;
if (maze[x][y] == '.'&&dis[u][id[x][y]] == -1) {
que.push(node{ P(x,y),v.dis + 1 });
dis[u][id[x][y]] = v.dis + 1;
}
}
}
}
int main() {
int t;
scanf("%d", &t); getchar();
while (t--) {
init(); d.clear(); p.clear();
memset(dis, -1, sizeof(dis));
memset(id, 0, sizeof(id));
scanf("%d%d", &n, &m); getchar();
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
maze[i][j] = getchar();
if (maze[i][j] == 'D')
d.push_back(P(i, j));
else if (maze[i][j] == '.') {
id[i][j] = p.size();
p.push_back(P(i, j));
}
}
getchar();
}
for (int i = 0; i < d.size(); i++)
bfs(i);
bool judge = false;
for (int i = 0; i < p.size(); i++) {
judge = true;
for (int j = 0; j < d.size(); j++) {
if (dis[j][i] >= 0) {
judge = false;
break;
}
}
if (judge)
break;
}
if (judge) {
puts("impossible");
continue;
}
int cnt = 0, ans = 0;
memset(match, -1, sizeof(match));
int now = p.size();
while (cnt < p.size()) {
ans++;
for (int i = 0; i < d.size(); i++) {
for (int j = 0; j < p.size(); j++) {
if (0 <= dis[i][j] && dis[i][j] <= ans)
addEdge(now, j);
}
memset(used, 0, sizeof(used));
if (dfs(now))
cnt++;
now++;
}
}
printf("%d\n", ans);
}
return 0;
}