题目链接:http://poj.org/problem?id=3057
题意:在一个X * Y的区域内,每个点可能是墙壁,门,空区域的人,现在房间起火了,每个门每秒只允许一个人通过,每个人每秒只能移动一步,求最后一个人逃脱的最短时间,如果有人无法逃脱,输出"impossible"
思路:由于每秒只能通过一个人,所以不能广搜最大值作为答案,考虑一个门,能在时间t内逃脱的人,是在距离门t以内的人,并且只有一人能够从该门逃脱,每个时间和门的二元组,都确定一个对应的能够从中逃脱的人的几何,通过计算这个二元组和人的二分图的匹配数,即可判断所有人能否可以逃脱。如果按照二分来搜索结果,会有重复计算,考虑如果在已知的T时间无法逃脱,检查T1 > T 时,比较之前的图,只是增加了其中一侧的顶点和与之对应的边,而在二分图最大匹配算法中,它是按顺序从一侧的顶点开始寻找增广路增广。因此,要求T1对应的最大匹配,只要在已求得的最大匹配基础上,继续从新增加的顶点开始寻找增广路即可,故更有效的解法是直接每次将T递增1然后寻求对应的二分图最大匹配
挑战程序上的代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
#include <vector>
using namespace std;
const int maxn = 15;
const int maxd = 10010;
const int dx[4] = {-1, 0, 0, 1}, dy[4] = {0, -1, 1, 0};
int X, Y;
char field[maxn][maxn];
vector <int> dX, dY;
vector <int> pX, pY;
int dist[maxn][maxn][maxn][maxn];
vector <int> G[maxd];
int match[maxd];
bool used[maxd];
void add_adge(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[v] = u;
match[u] = v;
return true;
}
}
return false;
}
void bfs(int x, int y, int d[maxn][maxn])
{
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 x2 = x + dx[k], y2 = y + dy[k];
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()
{
dX.clear();
dY.clear();
pX.clear();
pY.clear();
int n = (X - 1) * (Y - 1);
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);
}
}
int d = dX.size(), p = pX.size();
for(int v = 0; v < n * d; 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_adge((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;
scanf("%d", &t);
while(t--)
{
scanf("%d %d", &X, &Y);
for(int i = 0; i < X; i++)
scanf("%s", field[i]);
solve();
}
return 0;
}