题目来源:http://poj.org/problem?id=3057
由于题目是让求所需花费的最小时间,因此可以采用二分答案的方法,验证答案是否可行。
可以采用最大流来验证是否存在方案。
建图方法:
假设有一个源点S,与图中所有的“.”相连,流量为1,图中所有的“.”与其所能到达的"D"相连,流量为1。图中所有的“D”与假设的汇点T相连,流量为二分的值mid,跑从S到T的最大流,如果最大流与图中的“.”的个数相等,则此方案可行。
代码:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <queue>
#include <cmath>
using namespace std;
int n,m,a[222][222],x[222],y[222],num1,num2,num[222][222],g[222][222];
namespace bfs {
queue<int> q;
int f[222][222];
int dx[] = {0, 0, 1, -1};
int dy[] = {1, -1, 0, 0};
void get_len(int tot) {
for (int k = 1; k <= num1; ++k) {
memset(f, 63, sizeof(f));
f[x[k]][y[k]] = 0;
while (!q.empty())q.pop();
q.push(x[k]);
q.push(y[k]);
while (!q.empty()) {
int x = q.front();
q.pop();
int y = q.front();
q.pop();
if (f[x][y] > tot)continue;
for (int i = 0; i < 4; ++i) {
if (x + dx[i] >= 1 && x + dx[i] <= n && y + dy[i] >= 1 && y + dy[i] <= m &&
a[x + dx[i]][y + dy[i]] == 0 && f[x + dx[i]][y + dy[i]] > f[x][y] + 1) {
f[x + dx[i]][y + dy[i]] = f[x][y] + 1;
q.push(x + dx[i]);
q.push(y + dy[i]);
}
}
}
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= m; ++j) {
if (f[i][j] <= tot && a[i][j] == 0) {
g[k][num[i][j]] = 1;
}
}
}
}
}
}
namespace wll {
const int maxn = 222;
const int maxm = 10001;
int cnt = 0, s, t, head[maxn];
bool vis[222];
struct edge {
int to, next, cap, rev;
} e[maxm];
void ins(int x, int y, int z) {
e[++cnt].to = y;
e[cnt].next = head[x];
head[x] = cnt;
e[cnt].cap = z;
e[cnt].rev = cnt + 1;
e[++cnt].to = x;
e[cnt].next = head[y];
head[y] = cnt;
e[cnt].cap = 0;
e[cnt].rev = cnt - 1;
}
void build(int tot) {
s = 0, t = num1 + num2 + 1;
cnt = 0;
memset(head, 0, sizeof(head));
for (int i = 1; i <= num2; ++i) {
ins(s, i, 1);
for (int j = 1; j <= num1; ++j) {
if (g[j][i])
ins(i, num2 + j, 1);
}
}
for (int i = 1; i <= num1; ++i) {
ins(num2 + i, t, tot);
}
}
int dfs(int v, int t, int f) {
if (v == t)return f;
vis[v] = 1;
for (int i = head[v]; i; i = e[i].next) {
if (!vis[e[i].to] && e[i].cap > 0) {
int d = dfs(e[i].to, t, min(f, e[i].cap));
if (d > 0) {
e[i].cap -= d;
e[e[i].rev].cap += d;
return d;
}
}
}
return 0;
}
int max_flow() {
int flow = 0;
for (;;) {
memset(vis, 0, sizeof(vis));
int f = dfs(s, t, 1e9);
if (f == 0)return flow;
flow += f;
}
}
}
bool can(int tot) {
memset(g, 0, sizeof(g));
bfs::get_len(tot);
wll::build(tot);
if (wll::max_flow() == num2)return 1;
return 0;
}
void solve() {
int l = 0, r = n * m + 10;
while (l < r) {
int mid = (l + r) / 2;
if (can(mid))r = mid;
else l = mid + 1;
}
if (l >= n * m)cout << "impossible" << endl;
else cout << l << endl;
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int _;
cin >> _;
while (_--) {
cin >> n >> m;
char c;
num1 = num2 = 0;
memset(a, 0, sizeof(a));
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= m; ++j) {
cin >> c;
if (c == '.') {
num[i][j] = ++num2;
a[i][j] = 0;
}
if (c == 'X')
a[i][j] = 1;
if (c == 'D') {
a[i][j] = 1;
x[++num1] = i;
y[num1] = j;
}
}
}
solve();
}
return 0;
}