题意
- 在一个用矩阵描述的房间里,每个非墙位置都有一个人
- 矩阵外侧一圈,是墙或者门
- 每个人移动一格的时间为1,但是每个时刻通过门的人数只能为1
- 问你最快所有人出房间的时间为多少
思路:
首先我们要 bfs 一遍,以每个门为起点,找人到门的最短距离,
然后我们不断增加时间,每个时间我们增加 门 的数量,增加的数量就是门的总数,然后在这个时间内可以逃脱的人向门连一条边,然后我们进行二分图匹配。如果得出的结果跟人数一样,那么这个时间就是最小时间,否则,我们在重复之前的操作。
知道最大匹配得出的结果和人数一样为止。
#include <iostream>
#include <queue>
#include <cstring>
#include <cstdio>
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std;
#define X first
#define Y second
#define mem(x,v) memset(x,v,sizeof(x))
typedef pair<int,int> P;
const int dx[4] = {-1,1,0,0};
const int dy[4] = {0,0,-1,1};
const int INF = 0x3f3f3f3f;
int dis[20][20][20][20];
int n,m,t,dl,pl;
bool used[50000],vv[20][20];
char ma[20][20];
vector<P>d,p;
vector<int> f[50000];
int linker[50000];
void bfs(int u, int v){
int x,y;
dis[u][v][u][v] = 0;
queue<P>que;
que.push(P(u,v));
while(!que.empty()) {
P uq = que.front(); que.pop();
int s = uq.X, t = uq.Y;
for (int i = 0; i < 4; i++) {
x = s + dx[i];
y = t + dy[i];
if (ma[x][y] == '.' && x >= 0 && x < n && y >= 0 && y < m && dis[u][v][x][y] > dis[u][v][s][t] + 1){
dis[u][v][x][y] = dis[u][v][s][t] + 1;
vv[x][y]= 1;
que.push(P(x,y));
}
}
}
}
bool dfs(int u){
for (int i = 0; i < f[u].size(); i++){
if (!used[f[u][i]]){
used[f[u][i]] = 1;
if (linker[f[u][i]] == -1 || dfs(linker[f[u][i]])){
linker[f[u][i]] = u;
return 1;
}
}
}
return 0;
}
int main() {
int T;
cin>>T;
while(T--){
scanf("%d%d",&n,&m);
for (int i = 0; i < n; i++)
cin>>ma[i];
d.clear(); p.clear();
mem(vv,0);
mem(dis,INF);
mem(linker,-1);
dl = 0,pl = 0;
for (int i = 0; i < n; i++){
for (int j = 0; j < m; j++){
if (ma[i][j] == 'D'){
d.push_back(P(i,j));
dl++;
bfs(i,j);
}
if (ma[i][j] == '.') p.push_back(P(i,j)),pl++;
}
}
/* for (int i = 0; i < n; i++){
for (int j = 0; j < m; j++)
printf("%d ",dis[d[0].X][d[0].Y][i][j]);
printf("\n");
} */
bool flag = 0;
for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++)
if (ma[i][j] == '.' && vv[i][j] == 0){
flag = 1;
break;
}
if (flag){
printf("impossible\n");
continue;
}
for (int i = 0; i < 40000; i ++)
f[i].clear();
t = 0;
int ans = 0;
for ( ; ; ){
for (int i = 0; i < dl; i++)
for (int j = 0; j < pl; j++)
if (dis[d[i].X][d[i].Y][p[j].X][p[j].Y] <= t + 1) f[t * dl + i].push_back(p[j].X*m+p[j].Y);
t++;
for (int i = (t-1)*dl; i < t * dl; i++){
mem(used,0);
if (dfs(i)) ans++;
}
if (ans >= pl) break;
}
printf("%d\n",t);
}
return 0;
}