zoukankan      html  css  js  c++  java
  • 【最大匹配+二分答案】POJ 3057 Evacuation

    题目大意

    POJ链接
    有一个(X×Y)的房间,X代表墙壁,D是门,.代表人。这个房间着火了,人要跑出去,但是每一个时间点只有一个人可以从门出去。
    问最后一个人逃出去的最短时间,如果不能逃出去,输出impossible

    输入格式

    第一行一个整数(T),表示有T组数据。
    每组数据,第一行两个数字(Y,X),接下来有一个(X×Y)的图。

    输出格式

    (T)行答案,表示最后一个人逃出去的最短时间,如果不能逃出去,输出impossible

    数据范围

    (3le Yle Xle 12)

    样例输入

    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),那么可以把从(t)到最大时间每一秒的这扇门和这个人建边,因为只要能到达,之后任何一秒都可以选择出去。从时间小的门的点开始匹配。看一下多长时间人和们都能匹配上。
    查询人到门的距离用BFS,而最后求答案要用二分。

    代码

    #include <cstdio>
    #include <queue>
    #include <cstring>
    using namespace std;
    const int maxn=1e6+10;
    const int dx[4]={0,0,1,-1};
    const int dy[4]={1,-1,0,0};
    int x,y;
    char g[20][20];
    int match[maxn];
    
    struct Edge{
        int to,nxt,val;
    }edge[maxn];
    
    struct Node{
        int x,y,t;
        Node(){}
        Node(int a,int b,int c){
            x=a;y=b;t=c;
        }
    };
    
    int head[maxn],tot;
    void add(int a,int b,int w){
        edge[++tot].to=b;
        edge[tot].val=w;
        edge[tot].nxt=head[a];
        head[a]=tot;
    }
    
    queue<Node> q;
    int cal1(int a,int b){
        return y*(a-1)+b;//两个数映射成一个数
    }
    
    int cal2(int a,int b,int t){
        return (cal1(a,b)-1)*100+t;
    }
    
    void add2(int a,int b,int xx,int yy,int t){
        for(int i=t;i<=100;i++)
            add(cal1(a,b),cal2(xx,yy,i),i);//把这个人和之后分成的多个门建边
    }
    
    bool vis[20][20];
    void bfs(int a,int b){
        memset(vis,0,sizeof(vis));
        vis[a][b]=true;
        q.push(Node(a,b,0));
        while(!q.empty()){
            Node now=q.front();q.pop();
    
            for(int i=0;i<4;i++){
                int xx=now.x+dx[i];
                int yy=now.y+dy[i];
    
                if(xx>=1&&xx<=x&&yy>=1&&yy<=y&&!vis[xx][yy]&&g[xx][yy]=='.'){
                    vis[xx][yy]=true;
                    q.push(Node(xx,yy,now.t+1));
                }
                
                if(xx>=1&&xx<=x&&yy>=1&&yy<=y&&!vis[xx][yy]&g[xx][yy]=='D'){
                    vis[xx][yy]=true;
                    add2(a,b,xx,yy,now.t+1);//找到了门
                }
            }
        }
    }
    
    bool vis2[maxn];
    bool dfs(int x,int t){
        for(int i=head[x];i;i=edge[i].nxt){
            if(vis2[edge[i].to]||edge[i].val>t)continue;
            vis2[edge[i].to]=true;
            if(match[edge[i].to]==0||dfs(match[edge[i].to],t)){
                match[edge[i].to]=x;
                return true;
            }
        }
        return false;
    }
    
    bool judge(int t){
        memset(match,0,sizeof(match));
        for(int i=1;i<=x;i++)
            for(int j=1;j<=y;j++)
                if(g[i][j]=='.'){
                    memset(vis2,0,sizeof(vis2));
                    if(!dfs(cal1(i,j),t))return false;
                }
        return true;
    }
    
    void arrclear(){
        memset(head,0,sizeof(head));
    
    }
    
    int main(){
        freopen("123.txt","r",stdin);
    
        int T;
        scanf("%d",&T);
        while(T--){
            arrclear();
            scanf("%d%d",&x,&y);
    
            tot=0;
            for(int i=1;i<=x;i++)
                for(int j=1;j<=y;j++)
                    scanf(" %c",&g[i][j]);
    
            for(int i=1;i<=x;i++)
                for(int j=1;j<=y;j++)
                    if(g[i][j]=='.')bfs(i,j);//找到人bfs
    
            int l=0,r=100;//卡的贼严,还是开小点
            while(l<=r){//二分答案
                int mid=(l+r)/2;
                if(judge(mid))r=mid-1;
                else l=mid+1;
            }
            if(l==100+1)printf("impossible
    ");
            else printf("%d
    ",l);
        }
        return 0;
    }
    
  • 相关阅读:
    WEB 文件上传
    solr 管理页面详解
    tomcat 修改端口
    solr 6.0 没有schema.xml未自动创建schema文件
    selenium 使用action进行鼠标,键盘操作
    Ubuntu1404安装eclipse(目的是为了运行python,当然java更可以)
    ubuntu1404安装
    如何在博客园中添加数学公式
    卷积cnn总结
    在Ubuntu1404的64bit版本下安装caffe
  • 原文地址:https://www.cnblogs.com/Midoria7/p/12901486.html
Copyright © 2011-2022 走看看