poj 3057

来源:互联网 发布:手机坐标放线软件 编辑:程序博客网 时间:2024/05/22 21:29

考虑某一个门,能在时间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();}}