zoukankan      html  css  js  c++  java
  • P3191 [HNOI2007]紧急疏散EVACUATE 最大流 二分

      

    题目描述

    发生了火警,所有人员需要紧急疏散!假设每个房间是一个N M的矩形区域。每个格子如果是'.',那么表示这是一块空地;如果是'X',那么表示这是一面墙,如果是'D',那么表示这是一扇门,人们可以从这儿撤出房间。已知门一定在房间的边界上,并且边界上不会有空地。最初,每块空地上都有一个人,在疏散的时候,每一秒钟每个人都可以向上下左右四个方向移动一格,当然他也可以站着不动。疏散开始后,每块空地上就没有人数限制了(也就是说每块空地可以同时站无数个人)。但是,由于门很窄,每一秒钟只能有一个人移动到门的位置,一旦移动到门的位置,就表示他已经安全撤离了。现在的问题是:如果希望所有的人安全撤离,最短需要多少时间?或者告知根本不可能。

    输入格式

    输入文件第一行是由空格隔开的一对正整数N与M,3<=N <=20,3<=M<=20,以下N行M列描述一个N M的矩阵。其中的元素可为字符'.'、'X'和'D',且字符间无空格。

    输出格式

    只有一个整数K,表示让所有人安全撤离的最短时间,如果不可能撤离,那么输出'impossible'(不包括引号)。

    输入输出样例

    输入 #1
    5 5
    XXXXX
    X...D
    XX.XX
    X..XX
    XXDXX
    输出 #1
    3


    #include<bits/stdc++.h>
    using namespace std;
    //input by bxd
    #define rep(i,a,b) for(int i=(a);i<=(b);i++)
    #define repp(i,a,b) for(int i=(a);i>=(b);--i)
    #define RI(n) scanf("%d",&(n))
    #define RII(n,m) scanf("%d%d",&n,&m)
    #define RIII(n,m,k) scanf("%d%d%d",&n,&m,&k)
    #define RS(s) scanf("%s",s);
    #define ll long long
    #define pb push_back
    #define REP(i,N)  for(int i=0;i<(N);i++)
    #define CLR(A,v)  memset(A,v,sizeof A)
    //////////////////////////////////
    #define inf 0x3f3f3f3f
    const int N=1e2+44;
    const int M=1e6+54;
    int d[N];
    struct edge {
        int to, next, w;
    } e[M << 1];
    int head[M],cur[M],cnt = 1;
    void add(int x, int y, int z) {
        e[++cnt] = (edge){y, head[x], z};
        head[x] = cnt;
        e[++cnt] = (edge){x, head[y], 0};
        head[y] = cnt;
    }
    void init()
    {
        cnt=1;CLR(head,0);CLR(cur,0);
    }
    void ins(int x,int y,int a,int b)
    {
        add(x,y,b-a);
        d[x]-=a;
        d[y]+=a;
    }
    
    int level[M];
    bool bfs(int s, int t) {
        memset(level, 0, sizeof level);
        queue<int> q;
        level[s] = 1;
        q.push(s);
        while (!q.empty()) {
            int pos = q.front();q.pop();
            for (int i = head[pos]; i; i = e[i].next) {
                int nx = e[i].to;
                if (!e[i].w || level[nx]) continue;
                level[nx] = level[pos] + 1;
                q.push(nx);
            }
        }
        return level[t];
    }
    int dfs(int s, int t, int flow) {
        if(s==t||flow==0)return flow;
    
        int f,ret = 0;
        for (int &i = cur[s],v; i; i = e[i].next) {
             v = e[i].to;
            if (level[v] == level[s] + 1 && (f=dfs(v,t,min(flow,e[i].w)))>0) {
                e[i].w -= f;
                e[i ^ 1].w += f;
                flow -= f;
                ret += f;
                if(!flow)break;
            }
        }
        return ret;
    }
    int dinic(int s, int t) {
        int ret = 0;
        while (bfs(s, t)) memcpy(cur,head,sizeof cur),ret += dfs(s, t, inf);
        return ret;
    }
    
    int n,m,s,t,a,b,c,sum,S,T,k;
    char mp[100][100],id[100][100],pos,posdoor;
    int dx[]={1,0,-1,0};
    int dy[]={0,-1,0,1};
    
    vector<pair<int,int> >door,peo[400+4];
    
    struct node
    {
        int x,y,d;
    }u,v;
    queue<node>q;
    
    int vis[100][100];
    
    bool check(int mid)
    {
        init();
        rep(i,1,pos)
        {
            add(s,i,1);
            for(int j=0;j<peo[i].size();j++)
            {
                if(peo[i][j].second<=mid)
                add(i,pos+2+mid*(peo[i][j].first)+peo[i][j].second,1);
            }
        }
        rep(i,1,posdoor)
        {
            rep(j,1,mid)
            {
                add( (i)*mid+j+pos+2,t,1);
                if(j!=mid)add( (i)*mid+j+pos+2,(i)*mid+j+pos+3,inf);
            }
        }
        return dinic(s,t)==pos;
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        rep(i,1,n)scanf("%s",mp[i]+1);
    
        rep(i,1,n)
        rep(j,1,m)
        if(mp[i][j]=='D')
        door.push_back(make_pair(i,j));
        else if(mp[i][j]=='.')
        id[i][j]=++pos;
    
        s=pos+1,t=s+1;
        posdoor=door.size();
        
        for(int i=0;i<door.size();i++)
        {
            CLR(vis,0);
            while(!q.empty())q.pop();
    
            u.x=door[i].first;
            u.y=door[i].second;
            u.d=0;vis[u.x][u.y]=1;
            q.push(u);int xx,yy;
            while(!q.empty())
            {
                u=q.front();q.pop();
                rep(j,0,3)
                {
                    v.x=u.x+dx[j];
                    v.y=u.y+dy[j];
                    v.d=u.d+1;
                    if(v.x>=1&&v.x<=n&&v.y>=1&&v.y<=m&&!vis[v.x][v.y]&&mp[v.x][v.y]=='.')
                    {
                        peo[id[v.x][v.y]].push_back(make_pair(i+1,v.d));
                        vis[v.x][v.y]=1;
                        q.push(v);
                    }
                }
            }
        }
        int ans=-1,R=1000,L=1;
        while(L<=R)
        {
            int mid=(L+R)>>1;
            if(check(mid))R=mid-1,ans=mid;
            else L=mid+1;
        }
        if(ans==-1)printf("impossible
    ");
        else printf("%d
    ",ans);
        return 0;
    }
    View Code



  • 相关阅读:
    考试 题目
    引用数据类型 Scanner和 Random
    数组
    数据字典 事物 序列 索引视图
    小程序下拉刷新
    使用e.target.dataset的问题
    动态统计当前输入内容的字节、字符数
    小程序根据input输入,动态设置按钮的样式
    小程序刨坑(一)
    charles 踩坑记录
  • 原文地址:https://www.cnblogs.com/bxd123/p/11314152.html
Copyright © 2011-2022 走看看