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
XXXXX
X...D
XX.XX
X..XX
XXDXX
Sample Output
3
今天去省冬被暴虐而归……本想刷刷水题,结果又被水题虐了……调了半天加边的时候手滑++cnt写成+cnt结果调了一晚上
就是二分+网络流。先预处理所有门到空地的距离。然后每次二分一个最短时间+dinic判定。S向空地连边,空地向能到的门连边,门再向T连边。最后判断是否流量==空地数
#include<cstdio> #include<cstring> #define S 0 #define T 1000 #define inf 0x7fffffff const int mx[4]={-1,0,1,0}; const int my[4]={0,1,0,-1}; int cnt=1,ans=-1,sum,tot; struct point{ int x,y; }d[401]; struct queue{ int x,y,t; }q[1001]; struct edge{ int from,to,next,v; }e[100000]; int n,m,doors,l,r; char ch[100]; int head[10001]; int h[10001]; int dist[401][21][21]; bool map[21][21]; bool flag[21][21]; inline int min(int a,int b) {return a<b?a:b;} inline void ins(int u,int v,int w) { e[++cnt].v=w; e[cnt].from=u; e[cnt].to=v; e[cnt].next=head[u]; head[u]=cnt; } inline void insert(int u,int v,int w) { ins(u,v,w); ins(v,u,0); } inline void search(int k) { memset(q,0,sizeof(q)); memset(flag,0,sizeof(flag)); int t=0,w=1; q[1].x=d[k].x; q[1].y=d[k].y; flag[q[1].x][q[1].y]=1; while (t<w) { int nx=q[++t].x,ny=q[t].y,nt=q[t].t; for (int i=0;i<4;i++) if (map[nx+mx[i]][ny+my[i]]&&!flag[nx+mx[i]][ny+my[i]]) { dist[k][nx+mx[i]][ny+my[i]]=nt+1; flag[nx+mx[i]][ny+my[i]]=1; q[++w].x=nx+mx[i]; q[w].y=ny+my[i]; q[w].t=nt+1; } } } inline bool bfs() { int que[10001]; memset(h,-1,sizeof(h)); int t=0,w=1; h[S]=0;que[1]=S; while (t<w) { int now=que[++t]; for (int i=head[now];i;i=e[i].next) if (e[i].v&&h[e[i].to]==-1) { que[++w]=e[i].to; h[e[i].to]=h[now]+1; } } if (h[T]==-1) return 0; return 1; } inline int dfs(int x,int f) { if (x==T||f==0) return f; int w,used=0; for (int i=head[x];i;i=e[i].next) if (e[i].v&&h[e[i].to]==h[x]+1) { w=f-used; w=dfs(e[i].to,min(e[i].v,w)); e[i].v-=w; e[i^1].v+=w; used+=w; } if (!used) h[x]=-1; return used; } inline void dinic() { while (bfs()) sum+=dfs(S,inf); } inline void buildmap(int time) { cnt=1;sum=0; memset(e,0,sizeof(e)); memset(head,0,sizeof(head)); for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) if (map[i][j]) insert(S,(i-1)*m+j,1); for (int i=1;i<=doors;i++) { insert(n*m+i+1,T,time); for (int j=1;j<=n;j++) for (int k=1;k<=m;k++) if (dist[i][j][k]<=time) insert((j-1)*m+k,n*m+i+1,time); } } inline bool jud(int k) { buildmap(k); for (int i=2;i<=cnt;i+=2) dinic(); return sum==tot; } int main() { scanf("%d%d",&n,&m); for (int i=1;i<=n;i++) { scanf("%s",ch); for(int j=1;j<=m;j++) { if (ch[j-1]=='.') { map[i][j]=1; tot++; } if (ch[j-1]=='D') { d[++doors].x=i; d[doors].y=j; } } } memset(dist,127/3,sizeof(dist)); for (int i=1;i<=doors;i++)search(i); l=0;r=400; while (l<=r) { int mid=(l+r)>>1; if (jud(mid)){ans=mid;r=mid-1;} else l=mid+1; } if(ans!=-1)printf("%d",ans); else printf("impossible"); return 0; }