zoukankan      html  css  js  c++  java
  • POJ 3057 Evacuation 题解

    题目

    Fires can be disastrous, especially when a fire breaks out in a room that is completely filled with people. Rooms usually have a couple of exits and emergency exits, but with everyone rushing out at the same time, it may take a while for everyone to escape.

    You are given the floorplan of a room and must find out how much time it will take for everyone to get out. Rooms consist of obstacles and walls, which are represented on the map by an 'X', empty squares, represented by a '.' and exit doors, which are represented by a 'D'. The boundary of the room consists only of doors and walls, and there are no doors inside the room. The interior of the room contains at least one empty square.

    Initially, there is one person on every empty square in the room and these persons should move to a door to exit. They can move one square per second to the North, South, East or West. While evacuating, multiple persons can be on a single square. The doors are narrow, however, and only one person can leave through a door per second.

    What is the minimal time necessary to evacuate everybody? A person is evacuated at the moment he or she enters a door square.

    输入格式

    The first line of the input contains a single number: the number of test cases to follow. Each test case has the following format:
    One line with two integers (Y) and (X), separated by a single space, satisfying (3 <= Y, X <= 12): the size of the room
    (Y) lines with (X) characters, each character being either 'X', '.', or 'D': a valid description of a room

    输出格式

    For every test case in the input, the output should contain a single line with the minimal evacuation time in seconds, if evacuation is possible, or "impossible", if it is not.

    样例输入

    3
    5 5
    XXDXX
    X...X
    D...X
    X...D
    XXXXX
    5 12
    XXXXXXXXXXXX
    X..........D
    X.XXXXXXXXXX
    X..........X
    XXXXXXXXXXXX
    5 5
    XDXXX
    X.X.D
    XX.XX
    D.X.X
    XXXDX
    

    样例输出

    3
    21
    impossible
    

    题解

    这道题要用二分图的最大匹配来做

    对于每一扇门,同一秒只能让一个人通过,那我们就为每一扇门在每一秒建一个节点。

    对于每一个人,假设他最快可以在 (t) 的时间到达门 (i),那就把(t)到最大时间(图的大小) 这些节点建边连到人 (j)

    如果在这个图上跑二分匹配,匹配的边 <(t)时的门(i), 人(j)> 就代表人 (j) 会在时间 (t) 时从门 (i) 逃脱。

    找最短时间, 不断地枚举点,从该点找增广路。当从时间小的门的点开始枚举,这就代表时间小的门会优先匹配。我们只需看看枚举到哪个时间的门的时候,总匹配数等于人的数量,也是就所有人都被匹配到时,程序就可以结束了。答案就是此时的时间。

    实现的时候, 可以从每个门做一次 bfs,来找各个人到各个点所需的时间

    代码

    #include <cstdio>
    #include <queue>
    #include <cstring>
    using namespace std;
    int V, X, Y, dxy[4][2] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
    char map[13][13];
    vector<int> G[50010], dx, dy, px, py;
    int match[50005], dist[13][13][13][13];
    bool vis[50005];
    void add(int u, int v) { G[u].push_back(v), G[v].push_back(u); }
    bool find(int v) {
        vis[v] = 1;
        for (int i = 0; i < G[v].size(); i++) {
            int u = G[v][i];
            if (match[u] == -1 || !vis[match[u]] && find(match[u]))
                return match[v] = u, match[u] = v, true;
        }
        return false;
    }
    void bfs(int x, int y, int d[13][13]) {
        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 nx = x + dxy[k][0], ny = y + dxy[k][1];
                if (0 <= nx && nx < X && 0 <= ny && ny < Y && map[nx][ny] == '.' && d[nx][ny] < 0) {
                    d[nx][ny] = d[x][y] + 1;
                    qx.push(nx), qy.push(ny);
                }
            }
        }
    }
    int main() {
        int t;
        scanf("%d", &t);
        while (t--) {
            scanf("%d%d", &X, &Y);
            for (int i = 0; i < X; i++) scanf("%s", map[i]);
            int n = X * Y;
            dx.clear(), dy.clear(), px.clear(), py.clear();
            memset(dist, -1, sizeof(dist));
            for (int x = 0; x < X; x++)
                for (int y = 0; y < Y; y++) {
                    if (map[x][y] == 'D') {
                        dx.push_back(x), dy.push_back(y), bfs(x, y, dist[x][y]);
                    } else if (map[x][y] == '.')
                        px.push_back(x), py.push_back(y);
                }
            int d = dx.size(), p = px.size();
            V = X * Y * d + p;
            for (int v = 0; v < V; ++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((k - 1) * d + i, n * d + j);
            if (p == 0) {
                puts("0");
                continue;
            }
            int res = 0, flag = 1;
            memset(match, -1, sizeof(match));
            for (int v = 0; v < n * d; v++) {
                memset(vis, 0, sizeof(vis));
                if (find(v) && ++res == p) {
                    printf("%d
    ", v / d + 1);
                    flag = 0;
                    break;
                }
            }
            if(flag)puts("impossible");
        }
    }
    
  • 相关阅读:
    RAW和JPEG的区别_ZT
    用户自定义基元UDP_ZT
    UDP用户自定义原语
    SR锁存器
    Matlab实现Butterworth滤波器 分类: 图像处理 2014-06-02 00:05 527人阅读 评论(0) 收藏
    egrep命令的实现 分类: 编译原理 2014-06-01 23:41 329人阅读 评论(0) 收藏
    随机L系统分形树 分类: 计算机图形学 2014-06-01 23:27 376人阅读 评论(0) 收藏
    matlab实现算术编解码 分类: 图像处理 2014-06-01 23:01 357人阅读 评论(0) 收藏
    命名管道实现进程间通信--石头、剪刀、布游戏 分类: linux 2014-06-01 22:50 467人阅读 评论(0) 收藏
    互斥锁与条件变量应用 2014-06-01 22:20 328人阅读 评论(0) 收藏
  • 原文地址:https://www.cnblogs.com/youxam/p/poj-3057.html
Copyright © 2011-2022 走看看