1689: [HNOI2007]紧急疏散evacuate
时间限制: 1 Sec 内存限制: 128 MB题目描述
发生了火警,所有人员需要紧急疏散!假设每个房间是一个N M的矩形区域。每个格子如果是".",那么表示这是一块空地;如果是"X",那么表示这是一面墙,如果是"D",那么表示这是一扇门,人们可以从这儿撤出房间。已知门一定在房间的边界上,并且边界上不会有空地。最初,每块空地上都有一个人,在疏散的时候,每一秒钟每个人都可以向上下左右四个方向移动一格,当然他也可以站着不动。疏散开始后,每块空地上就没有人数限制了(也就是说每块空地可以同时站无数个人)。但是,由于门很窄,每一秒钟只能有一个人移动到门的位置,一旦移动到门的位置,就表示他已经安全撤离了。现在的问题是:如果希望所有的人安全撤离,最短需要多少时间?或者告知根本不可能。
输入
输入文件第一行是由空格隔开的一对正整数N与M,3<=N <=20,3<=M<=20,以下N行M列描述一个N M的矩阵。其中的元素可为字符"."、"X"和"D",且字符间无空格。
输出
只有一个整数K,表示让所有人安全撤离的最短时间,如果不可能撤离,那么输出"impossible"(不包括引号)。
样例输入
5 5
XXXXX
X...D
XX.XX
X..XX
XXDXX
样例输出
3
因为每一秒门只能出一个人,所以人可能堵住。因此要把门按时间拆点,
而答案为二分时间,只要求出空地到每扇门的最短路(最短时间),然后把此空地与门连接(时间为最短路径到二分的时间),边权为一。
注意拆出的新点标号别重复。。身败名裂。。
#include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #include<queue> #define inf 100000000 using namespace std; int n,m,a[404][404],cnt=0,door[404],peo[404]; int tim[404][704],adj[5000000],s=0,dep[5000000],e; int S=0,T; char tu[25][25]; struct node { int v,l,next; } lu[5000100]; void add(int u,int v,int l) {lu[++e].v=v;lu[e].next=adj[u];adj[u]=e;lu[e].l=l;} int bfs() { memset(dep,0,sizeof(dep)); queue<int> q; dep[S]=1; q.push(S); while(!q.empty()) { int x=q.front();q.pop(); for(int i=adj[x];i!=-1;i=lu[i].next) { int to=lu[i].v; if(!dep[to]&&lu[i].l) { dep[to]=dep[x]+1; if(to==T) return 1; q.push(to); } } } return 0; } int dfs(int x,int fw){ if(x==T) return fw; int tmp=fw,k; for(int i=adj[x];i!=-1;i=lu[i].next){ int v=lu[i].v; if(lu[i].l && tmp && dep[v]==dep[x]+1){ k=dfs(v,min(tmp,lu[i].l)); if(!k){ dep[v]=0; continue; } lu[i].l-=k; lu[i^1].l+=k; tmp-=k; } } return fw-tmp; } int check(int len) { memset(adj,-1,sizeof(adj)); e=0; int sum=cnt; for(int i=1;i<=cnt;i++) if(door[i]) for(int j=1;j<=len;j++) tim[i][j]=(i-1)*len+cnt; T=300000; for(int i=1;i<=cnt;i++) if(peo[i]) { add(S,i,1),add(i,S,0); for(int j=1;j<=cnt;j++) if(door[j]) { int k=a[i][j]; for(k=a[i][j];k<=len;k++) add(i,tim[j][k],1),add(tim[j][k],i,0); } } for(int i=1;i<=cnt;i++) if(door[i]) { for(int j=1;j<=len;j++) add(tim[i][j],T,1),add(T,tim[i][j],0); } int ans=0,tt; while(bfs()) ans+=dfs(S,inf); if(ans>=s)return 1; return 0; } int main() { // freopen("data.in","r",stdin); // freopen("data.out","w",stdout); scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%s",tu[i]+1); memset(a,30,sizeof(a)); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) { cnt++; if(tu[i][j]=='.') { s++; peo[cnt]=1; if(i!=1&&(tu[i-1][j]=='.'||tu[i-1][j]=='D'))a[cnt][cnt-m]=1,a[cnt-m][cnt]=1; if(i!=n&&(tu[i+1][j]=='.'||tu[i+1][j]=='D'))a[cnt][cnt+m]=1,a[cnt+m][cnt]=1; if(j!=1&&(tu[i][j-1]=='.'||tu[i][j-1]=='D'))a[cnt][cnt-1]=1,a[cnt-1][cnt]=1; if(j!=m&&(tu[i][j+1]=='.'||tu[i][j+1]=='D'))a[cnt][cnt+1]=1,a[cnt+1][cnt]=1; } if(tu[i][j]=='D') { door[cnt]=1; } } for(int k=1;k<=cnt;k++) for(int i=1;i<=cnt;i++) for(int j=1;j<=cnt;j++) if(a[i][j]>a[i][k]+a[k][j]) a[i][j]=a[i][k]+a[k][j]; for(int i=1;i<=cnt;i++) if(peo[i]) { int p=1; for(int j=1;j<=cnt;j++) if(door[j]&&a[i][j]<1000) {p=0;break;} if(p==1) { printf("impossible"); exit(0); } } int l=0,r=600,mid,ans=600; while(l<=r) { mid=(l+r)/2; if(check(mid)) r=mid-1,ans=mid; else l=mid+1; } printf("%d",ans); }