bzoj 1189 [HNOI2007]紧急疏散evacuate 二分+网络流

[HNOI2007]紧急疏散evacuate

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 3626  Solved: 1059
[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

HINT

 

2015.1.12新加数据一组,鸣谢1756500824

 

题解:二分+二分图匹配吧,网络流可以,需要注意一下,一个时刻只能允许出去一个人,所以出口再裂几个点即可。

  1 #include<cstdio>
  2 const int M=4000000,inf=0x3f3f3f3f;
  3 int h[M],q[M],S,T;
  4 int es[M],enx[M],ev[M],e0[M],ep=2;
  5 int n,m;
  6 char s[64][64];
  7 bool bfs(){
  8     int ql=0,qr=0;
  9     for(int i=1;i<=T;i++)h[i]=0;
 10     h[S]=1;
 11     q[qr++]=S;
 12     while(ql!=qr){
 13         int w=q[ql++];
 14         for(int i=e0[w];i;i=enx[i]){
 15             if(!ev[i])continue;
 16             int u=es[i];
 17             if(h[u])continue;
 18             h[u]=h[w]+1;
 19             q[qr++]=u;
 20         }
 21     }
 22     return h[T];
 23 }
 24 int dfs(int w,int f){
 25     if(w==T)return f;
 26     int used=0,c;
 27     for(int i=e0[w];i;i=enx[i]){
 28         if(!ev[i])continue;
 29         int u=es[i];
 30         if(h[u]!=h[w]+1)continue;
 31         c=f-used;
 32         if(c>ev[i])c=ev[i];
 33         c=dfs(u,c);
 34         ev[i]-=c;
 35         ev[i^1]+=c;
 36         used+=c;
 37         if(f==used)return f;
 38     }
 39     if(f!=used)h[w]=0;
 40     return used;
 41 }
 42 void addedge(int a,int b,int f){
 43     es[ep]=b;enx[ep]=e0[a];ev[ep]=f;e0[a]=ep++;
 44     es[ep]=a;enx[ep]=e0[b];ev[ep]=0;e0[b]=ep++;
 45 }
 46 int xs[]={-1,0,1,0};
 47 int ys[]={0,-1,0,1};
 48 int qx[10000],qy[10000],tag[64][64],len[64][64],now=0;
 49 bool chk(int X){
 50     int pc=0;
 51     S=(n+2)*m+2+X*n*m;T=S+1;
 52     for(int i=0;i<=T;i++)e0[i]=0;ep=2;
 53     for(int i=1;i<=n;i++){
 54         for(int j=1;j<=m;j++){
 55             if(s[i][j]=='.')addedge(S,i*m+j,1),pc++;
 56             if(s[i][j]=='D'){
 57                 for(int c=0;c<=X;c++)addedge(i*m+j+c*n*m,T,1);
 58                 int ql=0,qr=0;
 59                 qx[0]=i;qy[0]=j;qr++;
 60                 ++now;
 61                 tag[i][j]=now;
 62                 len[i][j]=0;
 63                 while(ql<qr){
 64                     int x=qx[ql],y=qy[ql];ql++;
 65                     if(s[x][y]=='.'&&len[x][y]<=X)for(int c=len[x][y];c<=X;c++)addedge(x*m+y,i*m+j+c*n*m,1);
 66                     if(len[x][y]<=X)
 67                     for(int a=0;a<4;a++){
 68                         int x1=x+xs[a],y1=y+ys[a];
 69                         if((s[x1][y1]=='.')&&tag[x1][y1]!=now){
 70                             tag[x1][y1]=now;
 71                             len[x1][y1]=len[x][y]+1;
 72                             qx[qr]=x1;qy[qr]=y1;qr++;
 73                         }
 74                     }
 75                 }
 76             }
 77         }
 78     }
 79     while(bfs())pc-=dfs(S,inf);
 80     return !pc;
 81 }
 82 int main(){
 83     scanf("%d%d",&n,&m);
 84     for(int i=0;i<=51;i++)for(int j=0;j<=51;j++)s[i][j]='X';
 85     for(int i=1;i<=n;i++){
 86         scanf("%s",s[i]+1);
 87         s[i][m+1]='X';
 88     }
 89     int L=0,R=n*m+1,M;
 90     while(L<R){
 91         M=L+R>>1;
 92         if(chk(M))R=M;
 93         else L=M+1;
 94     }
 95     while(!chk(L)&&L<=n*m)++L;
 96     while(L>0&&chk(L-1))--L;
 97     if(L<=n*m)printf("%d\n",L);
 98     else puts("impossible");
 99     return 0;
100 }

 

posted @ 2018-04-14 20:23  Kaiser-  阅读(292)  评论(0编辑  收藏  举报