考虑某一个门,能在时间t从该门逃脱的人,应该是距离该门t以内的人,并且其中只有一人能够从该门逃脱。每个时间和门的二元组,都能确定一个对应的能够从中逃脱的人的集合,而通过计算这个二元组和人组成的二分图的匹配数,我们就可以判断所有人是否都可以逃脱。
#include <iostream>
#include <cstdio>
#include <vector>
#include <cstring>
#include <queue>
using namespace std;
const int dx[4] = {-1, 0, 0, 1}, dy[4] = {0, -1, 1, 0};
const int MAX_X = 20;
const int MAX_Y = 20;
const int MAX_V = 100000;
int X, Y;
char field[MAX_X][MAX_Y + 1]; //输入
vector<int> dX, dY; // 门的坐标
vector<int> pX, pY; // 人的坐标
vector<int> G[MAX_V]; //保存图
int dist[MAX_X][MAX_Y][MAX_X][MAX_Y]; //每个门到每个人的最短距离
int match[MAX_V];
bool used[MAX_V];
void add_edge(int u, int v) {
G[u].push_back(v);
G[v].push_back(u);
}
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[u] = v;
match[v] = u;
return true;
}
}
return false;
}
//bfs求最短距离
void bfs(int x, int y, int d[MAX_X][MAX_Y]) {
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 i = 0; i < 4; i++) {
int x2 = dx[i] + x, y2 = dy[i] + y;
if (0 <= x2 && x2 < X && 0 <= y2 && y2 < Y && field[x2][y2] == '.' && d[x2][y2] < 0) {
d[x2][y2] = d[x][y] + 1;
qx.push(x2);
qy.push(y2);
}
}
}
}
void solve() {
int n = X * Y;
dX.clear(); dY.clear();
pX.clear(); pY.clear();
for (int i = 0; i < MAX_V; i++)
G[i].clear();
memset(dist, -1, sizeof(dist));
for (int x = 0; x < X; x++) {
for (int y = 0; y < Y; y++) {
if (field[x][y] == 'D') {
dX.push_back(x);
dY.push_back(y);
bfs(x, y, dist[x][y]);
} else if (field[x][y] == '.') {
pX.push_back(x);
pY.push_back(y);
}
}
}
//建图:每个时间和门的二元组,都确定一个对应的能够从中逃脱的人的集合
//通过计算这个二元组的和人的匹配数,则可以判断是否所有人都逃脱了。
// 0 ~ d - 1 : 时间1对应的d个门
// d ~ 2 * d - 1 : 时间2对应的d个门
// ……
// (n - 1) * d ~ n * d - 1 : 时间n-1对应的d个门
// n * d ~ n * d + p - 1: p个人
int d = dX.size(), p = pX.size();
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_edge((k - 1) * d + i, n * d + j);
}
}
}
}
if (p == 0) {
printf("0\n");
return;
}
int num = 0;
memset(match, -1, sizeof(match));
for (int v = 0; v < n * d; v++) {
memset(used, 0, sizeof(used));
if (dfs(v)) {
if (++num == p) {
printf("%d\n", v / d + 1);
return;
}
}
}
printf("impossible\n");
}
int main() {
int t;
cin >> t;
while(t--) {
cin >> X >> Y;
for (int i = 0; i < X; i++) {
scanf("%s", field[i]);
}
solve();
}
}