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

    1189: [HNOI2007]紧急疏散evacuate

    Time Limit: 10 Sec  Memory Limit: 162 MB
    Submit: 1132  Solved: 412
    [Submit][Status][Discuss]

    Description

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

    Input

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

    Output

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

    Sample Input

    5 5
    XXXXX
    X...D
    XX.XX
    X..XX
    XXDXX

    Sample Output

    3
     
     
    题解:S-'.'-'D'-T;先从门bfs出每个‘.’点到门的距离,注意要每种情况都要计算所以开一个距离数组400*20*20+1,再二分时间为最后‘D’到T的容量;
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<string>
    #include<algorithm>
    #include<queue>
    #include<cmath>
    #include<map>
    using namespace std ;
    typedef long long ll;
    inline ll read()
    {
        ll x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    //******************************************************************
    namespace NetFlow
    {
        const int MAXN=100000,MAXM=1000000,inf=1e9;
        struct Edge
        {
            int v,c,f,nx;
            Edge() {}
            Edge(int v,int c,int f,int nx):v(v),c(c),f(f),nx(nx) {}
        } E[MAXM];
        int G[MAXN],cur[MAXN],pre[MAXN],dis[MAXN],gap[MAXN],N,sz;
        void init(int _n)
        {
            N=_n,sz=0; memset(G,-1,sizeof(G[0])*N);
        }
        void link(int u,int v,int c)
        {
            E[sz]=Edge(v,c,0,G[u]); G[u]=sz++;
            E[sz]=Edge(u,0,0,G[v]); G[v]=sz++;
        }
        int ISAP(int S,int T)
        {//S -> T
            int maxflow=0,aug=inf,flag=false,u,v;
            for (int i=0;i<N;++i)cur[i]=G[i],gap[i]=dis[i]=0;
            for (gap[S]=N,u=pre[S]=S;dis[S]<N;flag=false)
            {
                for (int &it=cur[u];~it;it=E[it].nx)
                {
                    if (E[it].c>E[it].f&&dis[u]==dis[v=E[it].v]+1)
                    {
                        if (aug>E[it].c-E[it].f) aug=E[it].c-E[it].f;
                        pre[v]=u,u=v; flag=true;
                        if (u==T)
                        {
                            for (maxflow+=aug;u!=S;)
                            {
                                E[cur[u=pre[u]]].f+=aug;
                                E[cur[u]^1].f-=aug;
                            }
                            aug=inf;
                        }
                        break;
                    }
                }
                if (flag) continue;
                int mx=N;
                for (int it=G[u];~it;it=E[it].nx)
                {
                    if (E[it].c>E[it].f&&dis[E[it].v]<mx)
                    {
                        mx=dis[E[it].v]; cur[u]=it;
                    }
                }
                if ((--gap[dis[u]])==0) break;
                ++gap[dis[u]=mx+1]; u=pre[u];
            }
            return maxflow;
        }
        bool bfs(int S,int T)
        {
            static int Q[MAXN]; memset(dis,-1,sizeof(dis[0])*N);
            dis[S]=0; Q[0]=S;
            for (int h=0,t=1,u,v,it;h<t;++h)
            {
                for (u=Q[h],it=G[u];~it;it=E[it].nx)
                {
                    if (dis[v=E[it].v]==-1&&E[it].c>E[it].f)
                    {
                        dis[v]=dis[u]+1; Q[t++]=v;
                    }
                }
            }
            return dis[T]!=-1;
        }
        int dfs(int u,int T,int low)
        {
            if (u==T) return low;
            int ret=0,tmp,v;
            for (int &it=cur[u];~it&&ret<low;it=E[it].nx)
            {
                if (dis[v=E[it].v]==dis[u]+1&&E[it].c>E[it].f)
                {
                    if (tmp=dfs(v,T,min(low-ret,E[it].c-E[it].f)))
                    {
                        ret+=tmp; E[it].f+=tmp; E[it^1].f-=tmp;
                    }
                }
            }
            if (!ret) dis[u]=-1; return ret;
        }
        int dinic(int S,int T)
        {
            int maxflow=0,tmp;
            while (bfs(S,T))
            {
                memcpy(cur,G,sizeof(G[0])*N);
                while (tmp=dfs(S,T,inf)) maxflow+=tmp;
            }
            return maxflow;
        }
    }
    struct sss
    {
        int x,y,t;
    }hh[30][30];
    int n,m;
    int ss[4][2]={-1,0,0,-1,1,0,0,1};
    int tim[405][30][30];
    char mp[30][30];
    int tot;
    int cnt=0;
    int xxx[401],yyy[401];
    void bfss(int a,int b,int index)
    {
        sss k,kk;
        queue<sss>q;
        k.x=a;
        k.y=b;
        k.t=0;
        q.push(k);
        while(!q.empty())
        {
            kk=q.front();
            q.pop();
            for(int i=0;i<4;i++)
            {
                int xx=kk.x+ss[i][0];
                int yy=kk.y+ss[i][1];
                if(xx<=0||xx>n||yy<=0||yy>m)continue;
                if(mp[xx][yy]=='X'||mp[xx][yy]=='D')continue;
                if(kk.t+1<tim[index][xx][yy]){
                    tim[index][xx][yy]=kk.t+1;
                    hh[xx][yy].x=a;
                    hh[xx][yy].y=b;
                    sss kkk;
                    kkk.x=xx;
                    kkk.y=yy;
                    kkk.t=tim[index][xx][yy];
    
                   // cout<<"feinds "<<tim[xx][yy]<<endl;return;
                    q.push(kkk);
                }
            }
        }
    }
    using namespace NetFlow;
    int juge(int r)
    {
        init(3000);
        for(int i=1;i<=n;i++){
            for(int j=1;j<=m;j++)
            {
                if(mp[i][j]=='.')
                    link(1000,(i-1)*m+j,1);
            }
        }
        for(int i=1;i<=cnt;i++)link(n*m+i,1001,r);
        for(int i=1;i<=cnt;i++)
        {
            for(int j=1;j<=n;j++){
                for(int k=1;k<=m;k++)
                {
                    if(tim[n*m+i][j][k]<=r)link((j-1)*m+k,n*m+i,1);
                }
            }
        }
       // cout<<14<<endl;
        if(dinic(1000,1001)==tot)return 1;
        else return 0;
    }
    int main()
    {
    
        scanf("%d%d",&n,&m);
        tot=0;
        for(int i=1;i<=n;i++)
        {
            scanf("%s",mp[i]+1);
            for(int j=1;j<=m;j++)
            {
                if(mp[i][j]=='D')
                {
                    cnt++;
                    xxx[cnt]=i;
                    yyy[cnt]=j;
                }
                if(mp[i][j]=='.')tot++;
            }
        }
       // cout<<"das "<<tot<<endl;
        memset(tim,127,sizeof(tim));
       // if(cnt==0){cout<<"impossible"<<endl;return 0;}
        for(int i=1;i<=cnt;i++)
        {
            bfss(xxx[i],yyy[i],n*m+i);
        }
        int l=0;
        int r=400;
        int ans=-1;
        while(l<r)
        {
            int mid=(l+r)>>1;
            if(juge(mid))
            {
                ans=mid;
                r=mid;
            }
            else l=mid+1;
        }
        if(ans==-1)cout<<"impossible"<<endl;
        else
        cout<<ans<<endl;
        return 0;
    }
    代码

    例子:

    4 5
    XXDXX
    XX.XX
    X...X
    XXDXX

    答案应该输出3

    上面的做法是错的,必须要对门的每个时间点都连一条容量为limit-k+1的边才行,

    #include<bits/stdc++.h>
    using namespace std;
    #pragma comment(linker, "/STACK:102400000,102400000")
    #define ls i<<1
    #define rs ls | 1
    #define mid ((ll+rr)>>1)
    #define pii pair<int,int>
    #define MP make_pair
    typedef long long LL;
    const long long INF = 1e18+1LL;
    const double Pi = acos(-1.0);
    const int N = 5e4+500, M = 1e3+20, mod = 1e9+7, inf = 2e9;
    
    int n,m,vis[30][30],step[30][30],all;
    char mp[30][30];
    
    vector< pair<int,int > > D;
    vector< pair<int,int > > out[N];
    int ss[4][2] = {-1,0,0,-1,1,0,0,1};
    
    int h[N],head[N],t = 2,S,T,q[N],ans;
    struct edge{int to,next,v;}e[5000010];
    void adds(int u,int v,int w) {e[t].next=head[u];e[t].v=w;e[t].to=v;head[u]=t++;}
    void add(int u,int v,int w) {adds(u,v,w);adds(v,u,0);}
    
    
    int bfs() {
        memset(h,-1,sizeof(h));
        int l = 0,r = 1, now;
        q[l] = S;
        h[S] = 0;
        while(l != r) {
            now=q[l++];//if(l == 910)l = 0;
            for(int i=head[now];i!=-1;i=e[i].next) {
                if(e[i].v&&h[e[i].to] == -1) {
                    h[e[i].to] = h[now] + 1;
                    q[r++] = e[i].to;
                    //if(r == 910) r = 0;
                }
            }
        }
        if(h[T] == -1) return 0;
        return 1;
    }
    int dfs(int x,int f) {
        if(x == T) return f;
        int used=0,w;
        for(int i=head[x];i!=-1;i=e[i].next) {
            if(e[i].v&&h[e[i].to] == h[x]+1) {
                w=dfs(e[i].to,min(f-used,e[i].v));
                used+=w;e[i].v-=w;e[i^1].v+=w;
                if(used == f) return f;
            }
        }
        return used;
    }
    int dinic() {
       while(bfs()) {ans+=dfs(S,inf);}
       return ans;
    }
    
    int check(int x) {
         S = n*m+1,T = S + 1;
         t = 2, memset(head,-1,sizeof(head));
         int tot = 1;
         for(int i = 1; i <= n; ++i) {
            for(int j = 1; j <= m; ++j) {
                if(mp[i][j] == '.') {
                    add(S,(i-1)*m+j,1);
                    for(int k = 0; k < out[(i-1)*m+j].size(); ++k) {
                        if(out[(i-1)*m+j][k].first <= x)
                            add((i-1)*m+j,T+(out[(i-1)*m+j][k].second-1)*x+out[(i-1)*m+j][k].first,1);
                    }
                }
                if(mp[i][j] == 'D')  {
                    add((i-1)*m+j,T,x);
                    for(int k = 1; k <= x; ++k) add(T+(tot-1)*x+k,(i-1)*m+j,x-k+1);
                    tot++;
                }
            }
         }
         ans = 0;
         if(dinic() == all) return 1;
         else return 0;
    }
    
    void bfs(int x,int y,int who) {
        queue< pair<int ,int > >  q;
        q.push(MP(x,y));
        vis[x][y] = 1;
        step[x][y] = 0;
        while(!q.empty()) {
            pair<int,int > k = q.front();
            q.pop();
            for(int i = 0 ; i < 4; ++i) {
                int xx = k.first + ss[i][0];
                int yy = k.second + ss[i][1];
    
                if(xx <= 0 || yy <= 0 || xx > n || yy > m || mp[xx][yy] != '.') continue;
                if(vis[xx][yy]) continue;
    
                vis[xx][yy] = 1;
    
                q.push(MP(xx,yy));
                step[xx][yy] = step[k.first][k.second]+1;
                out[(xx-1)*m+yy].push_back(MP(step[xx][yy],who));
            }
        }
    }
    int main() {
        scanf("%d%d",&n,&m);
        for(int i = 1; i <= n; ++i) {
            scanf("%s",mp[i]+1);
            for(int j = 1; j <= m; ++j) {
                if(mp[i][j] == 'D') D.push_back(MP(i,j));
                if(mp[i][j] == '.') all++;
            }
        }
    
        for(int i = 0; i < D.size(); ++i) {
            memset(vis,0,sizeof(vis));
            memset(step,0,sizeof(step));
            bfs(D[i].first,D[i].second,i+1);
        }
        int l = 0, r = 400, ans1 = -1;
        while(l <= r) {
            int md = (l+r)>>1;
            if(check(md)) ans1 = md, r = md - 1;
            else l = md + 1;
        }
        if(ans1 == -1) printf("impossible");
        else printf("%d",ans1);
        return 0;
    }
    修改
  • 相关阅读:
    回顾:异常处理,值传递和引用传递
    回顾:静态变量和实例变量、构造器
    多态、抽象类与接口
    回顾:面向对象、基本类型
    总结一下《深入理解Java虚拟机》
    百度实习生面试题
    面试题
    阿里面试
    Shell
    Collector详解
  • 原文地址:https://www.cnblogs.com/zxhl/p/4769007.html
Copyright © 2011-2022 走看看