Description
发生了火警,所有人员需要紧急疏散!假设每个房间是一个N M的矩形区域。每个格子如果是'.',那么表示这是一块空地;如果是'X',那么表示这是一面墙,如果是'D',那么表示这是一扇门,人们可以从这儿撤出房间。已知门一定在房间的边界上,并且边界上不会有空地。最初,每块空地上都有一个人,在疏散的时候,每一秒钟每个人都可以向上下左右四个方向移动一格,当然他也可以站着不动。疏散开始后,每块空地上就没有人数限制了(也就是说每块空地可以同时站无数个人)。但是,由于门很窄,每一秒钟只能有一个人移动到门的位置,一旦移动到门的位置,就表示他已经安全撤离了。现在的问题是:如果希望所有的人安全撤离,最短需要多少时间?或者告知根本不可能。
Input
输入文件第一行是由空格隔开的一对正整数N与M,3<=N <=20,3<=M<=20,以下N行M列描述一个N M的矩阵。其中的元素可为字符'.'、'X'和'D',且字符间无空格。
Output
只有一个整数K,表示让所有人安全撤离的最短时间,如果不可能撤离,那么输出'impossible'(不包括引号)。
二分答案,对答案ans,把每个门拆成ans个点表示每个时刻,每个人到能在规定时间内到达的门连边,得到二分图,若最大匹配为人数则为可行解
#include<cstdio> const int M=4000000,inf=0x3f3f3f3f; int h[M],q[M],S,T; int es[M],enx[M],ev[M],e0[M],ep=2; int n,m; char s[64][64]; bool bfs(){ int ql=0,qr=0; for(int i=1;i<=T;i++)h[i]=0; h[S]=1; q[qr++]=S; while(ql!=qr){ int w=q[ql++]; for(int i=e0[w];i;i=enx[i]){ if(!ev[i])continue; int u=es[i]; if(h[u])continue; h[u]=h[w]+1; q[qr++]=u; } } return h[T]; } int dfs(int w,int f){ if(w==T)return f; int used=0,c; for(int i=e0[w];i;i=enx[i]){ if(!ev[i])continue; int u=es[i]; if(h[u]!=h[w]+1)continue; c=f-used; if(c>ev[i])c=ev[i]; c=dfs(u,c); ev[i]-=c; ev[i^1]+=c; used+=c; if(f==used)return f; } if(f!=used)h[w]=0; return used; } void addedge(int a,int b,int f){ es[ep]=b;enx[ep]=e0[a];ev[ep]=f;e0[a]=ep++; es[ep]=a;enx[ep]=e0[b];ev[ep]=0;e0[b]=ep++; } int xs[]={-1,0,1,0}; int ys[]={0,-1,0,1}; int qx[10000],qy[10000],tag[64][64],len[64][64],now=0; bool chk(int X){ int pc=0; S=(n+2)*m+2+X*n*m;T=S+1; for(int i=0;i<=T;i++)e0[i]=0;ep=2; for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ if(s[i][j]=='.')addedge(S,i*m+j,1),pc++; if(s[i][j]=='D'){ for(int c=0;c<=X;c++)addedge(i*m+j+c*n*m,T,1); int ql=0,qr=0; qx[0]=i;qy[0]=j;qr++; ++now; tag[i][j]=now; len[i][j]=0; while(ql<qr){ int x=qx[ql],y=qy[ql];ql++; 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); if(len[x][y]<=X) for(int a=0;a<4;a++){ int x1=x+xs[a],y1=y+ys[a]; if((s[x1][y1]=='.')&&tag[x1][y1]!=now){ tag[x1][y1]=now; len[x1][y1]=len[x][y]+1; qx[qr]=x1;qy[qr]=y1;qr++; } } } } } } while(bfs())pc-=dfs(S,inf); return !pc; } int main(){ scanf("%d%d",&n,&m); for(int i=0;i<=51;i++)for(int j=0;j<=51;j++)s[i][j]='X'; for(int i=1;i<=n;i++){ scanf("%s",s[i]+1); s[i][m+1]='X'; } int L=0,R=n*m+1,M; while(L<R){ M=L+R>>1; if(chk(M))R=M; else L=M+1; } while(!chk(L)&&L<=n*m)++L; while(L>0&&chk(L-1))--L; if(L<=n*m)printf("%d\n",L); else puts("impossible"); return 0; }