POJ - 3057 -- Evacuation

题目来源: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;
}

猜你喜欢

转载自blog.csdn.net/moon_sky1999/article/details/81390278