BZOJ1189[HNOI2007]紧急疏散evacuate 动态加边网络流
Posted CQzhangyu
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ1189[HNOI2007]紧急疏散evacuate 动态加边网络流相关的知识,希望对你有一定的参考价值。
【BZOJ1189】[HNOI2007]紧急疏散evacuate
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
XXXXX
X...D
XX.XX
X..XX
XXDXX
Sample Output
题解:这题网上好多题解都过不了,自己也狂WA不止,还好有小号交题大法~
先以每个门为起点进行BFS,将每个门按照时间拆点,设i号位置到j号门的距离为dis,则
i -> (j,dis) 容量1
S -> i 容量1
然后枚举时间,动态加边,设当前时间为tim,则
(j,tim-1) -> (j,tim) 容量∞
(j,tim) -> T 容量1
然后注意BFS的时候只能访问‘.‘的点,不能访问其他的门
#include <cstdio> #include <cstring> #include <iostream> #include <queue> #define tx (i+dx[k]) #define ty (j+dy[k]) #define P(A,B) ((A-1)*m+B) using namespace std; int to[4000010],next[4000010],val[4000010],head[200000],d[200000],dis[30][30]; int dx[]={1,0,-1,0},dy[]={0,1,0,-1}; int n,m,cnt,S,T,ans,tim,tot,dor; char str[30][30]; queue<int> q,qx,qy; int dfs(int x,int mf) { if(x==T) return mf; int i,temp=mf,k; for(int i=head[x];i!=-1;i=next[i]) { if(d[to[i]]==d[x]+1&&val[i]) { k=dfs(to[i],min(temp,val[i])); if(!k) d[to[i]]=0; val[i]-=k,val[i^1]+=k,temp-=k; if(!temp) break; } } return mf-temp; } int bfs() { memset(d,0,sizeof(d)); while(!q.empty()) q.pop(); int i,u; q.push(S),d[S]=1; while(!q.empty()) { u=q.front(),q.pop(); for(i=head[u];i!=-1;i=next[i]) { if(!d[to[i]]&&val[i]) { d[to[i]]=d[u]+1; if(to[i]==T) return 1; q.push(to[i]); } } } return 0; } void add(int a,int b,int c) { to[cnt]=b,val[cnt]=c,next[cnt]=head[a],head[a]=cnt++; to[cnt]=a,val[cnt]=0,next[cnt]=head[b],head[b]=cnt++; } void getdis(int x,int y) { memset(dis,0,sizeof(dis)); qx.push(x),qy.push(y); int i,j,k; while(!qx.empty()) { i=qx.front(),j=qy.front(),qx.pop(),qy.pop(); for(k=0;k<4;k++) if(!dis[tx][ty]&&tx&&tx<=n&&ty&&ty<=m&&str[tx][ty-1]==‘.‘) { dis[tx][ty]=dis[i][j]+1; add(P(tx,ty),P(x,y)+(dis[tx][ty]-1)*n*m,1); qx.push(tx),qy.push(ty); } } } int main() { scanf("%d%d",&n,&m); int i,j,k; S=0,T=n*m*n*m+1; memset(head,-1,sizeof(head)); for(i=1;i<=n;i++) scanf("%s",str[i]); for(i=1;i<=n;i++) for(j=1;j<=m;j++) { if(str[i][j-1]==‘.‘) tot++,add(S,P(i,j),1); if(str[i][j-1]==‘D‘) getdis(i,j); } while(ans<tot) { if(tim>=n*m) { printf("impossible"); return 0; } for(i=1;i<=n;i++) for(j=1;j<=m;j++) { if(str[i][j-1]==‘D‘) { add(P(i,j)+tim*n*m,T,1); if(tim) add(P(i,j)+(tim-1)*n*m,P(i,j)+tim*n*m,1<<30); } } tim++; while(bfs()) ans+=dfs(S,1<<30); } printf("%d",tim); return 0; }
以上是关于BZOJ1189[HNOI2007]紧急疏散evacuate 动态加边网络流的主要内容,如果未能解决你的问题,请参考以下文章
BZOJ 1189[HNOI2007]紧急疏散evacuate
[bzoj1189] [HNOI2007]紧急疏散evacuate
BZOJ1189[HNOI2007]紧急疏散evacuate 动态加边网络流
BZOJ 1189 [HNOI2007]紧急疏散evacuate