• POJ Evacuation /// 二分图最大匹配


    题目大意:

    在一个n*m的房间中 ‘X’为墙 ‘D’为门 ‘.’为人 

    门只存在与外围 人每秒钟只能向四连通区域走一步

    门比较狭窄 每秒钟只能通过一个人

    求所有人逃脱的最短时间 如果不可能则输出impossible

    对每个门 广搜出能在这个门逃脱的人的逃出时间

    将 对应各个时间的这个门 当做不同的点

    即 若有d个门 p个人

    时间1对应的门编号为 0~d-1

    时间2对应的门编号为 d~2*d-1

    时间t对应的门编号为 (t-1)*d~t*d-1

    然后将人编号为 t*d~t*d+p-1

    再将 对应时间的门的编号 与 对应时间在该门逃脱的人 连边

    而一个人若能在 t 时间逃脱 那么同样可以在 t+1、t+2、t+3...时间逃脱

    所以 对应时间到最晚时间的该门的编号 都可与 这个人连边

    这样找到 各个时间的门 与 人 的最大匹配

    时间从小到大 这样判断到最大匹配数恰好等于人数时说明此时所有人都可逃脱

    #include <bits/stdc++.h>
    using namespace std;
    int n,m;
    char G[15][15];
    int mov[4][2]={0,1,1,0,0,-1,-1,0};
    
    int dis[15][15][15][15]; 
    // dis[x][y][i][j] 门的位置为xy 人的位置为ij 保存逃脱的最短用时
    struct NODE { int x,y; };
    vector <NODE> D, P; // D记录门的位置 P记录人的位置
    
    const int E=12*12*12*15;
    vector <int> e[E]; // 邻接表
    
    bool bound(int x1,int y1) {
        return x1<0 || x1>=n || y1<0 || y1>=m;
    }
    void bfs(int x1,int y1,int d[15][15]) {
        // d为dis[x1][y1]对应的后两维 
        queue <NODE> q;
        q.push((NODE){x1,y1});
        d[x1][y1]=0;
        while(!q.empty()) {
            NODE e=q.front(); q.pop();
            for(int i=0;i<4;i++) {
                int x2=e.x+mov[i][0], y2=e.y+mov[i][1];
                if(bound(x2,y2) || d[x2][y2]!=-1) continue;
                if(G[x2][y2]!='.') continue;
                d[x2][y2]=d[e.x][e.y]+1;
                q.push((NODE){x2,y2});
            }
        }
    }
    /**二分图最大匹配*/
    bool vis[E];
    int mat[E];
    bool dfs(int u) {
        vis[u]=1;
        for(int i=0;i<e[u].size();i++) {
            int v=e[u][i], d=mat[v];
            if(d==-1 || !vis[d]&&dfs(d)) {
                mat[u]=v, mat[v]=u;
                return 1;
            }
        }
        return 0;
    }
    int match(int d,int p) {
        int res=0;
        memset(mat,-1,sizeof(mat));
        for(int i=0;i<n*d;i++) // 时间从小到大 一旦找到最大匹配就是最快逃脱时间
            if(mat[i]==-1) {
                memset(vis,0,sizeof(vis));
                if(dfs(i)) {
                    res++;
                    if(res==p) return i/d+1; 
                    /// 一旦匹配数等于人数 说明此时所有人都已匹配
                }
            }
        return 0;
    }
    /***/
    
    void solve() {
        memset(dis,-1,sizeof(dis));
        D.clear(), P.clear();
        for(int i=0;i<n;i++) {
            for(int j=0;j<m;j++)
                if(G[i][j]=='D') {
                    D.push_back((NODE){i,j});
                    bfs(i,j,dis[i][j]);// 广搜出所有能到ij门的人的最短时间
                } else if(G[i][j]=='.')
                    P.push_back((NODE){i,j});
        }
    
        n*=m;
        for(int i=0;i<E;i++) e[i].clear();
        int d=D.size(), p=P.size();
        for(int i=0;i<d;i++) {
            for(int j=0;j<p;j++) {
                int t=dis[D[i].x][D[i].y][P[j].x][P[j].y];
                if(t!=-1) { // 说明最快t时间可以逃脱
                    for(int k=t;k<=n;k++) // 则t以上时间都可逃脱 连边
                        e[(k-1)*d+i].push_back(n*d+j);
                }
            }
        }
    
        if(p==0) {
            printf("0
    "); return;
        }
        int ans=match(d,p);
        if(ans) printf("%d
    ",ans);
        else printf("impossible
    ");
    }
    
    int main()
    {
        int t; scanf("%d",&t);
        while(t--) {
            scanf("%d%d",&n,&m);
            for(int i=0;i<n;i++)
                scanf("%s",G[i]);
            solve();
        }
    
        return 0;
    }
    View Code
  • 相关阅读:
    nat
    ICE协议下NAT穿越的实现(STUN&TURN)
    比特币源码分析--端口映射
    IO复用,AIO,BIO,NIO,同步,异步,阻塞和非阻塞 区别(百度)
    从数据的角度带你深入了解IPFS
    IPFS 到底是怎么工作的?
    从数据的角度带你深入了解IPFS
    IPFS
    IPFS中文简介
    bootstrap 表单验证 dem
  • 原文地址:https://www.cnblogs.com/zquzjx/p/10121424.html
Copyright © 2020-2023  润新知