[bzoj1189] [HNOI2007]紧急疏散evacuate
Posted FallDream
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[bzoj1189] [HNOI2007]紧急疏散evacuate相关的知识,希望对你有一定的参考价值。
来自FallDream的博客,未经允许,请勿转载,谢谢。
-----------------------------------------------------------------------------
题目:发生了火警,所有人员需要紧急疏散!假设每个房间是一个N M的矩形区域。每个格子如果是‘.‘,那么表示这是一块空地;如果是‘X‘,那么表示这是一面墙,如果是‘D‘,那么表示这是一扇门,人们可以从这儿撤出房间。已知门一定在房间的边界上,并且边界上不会有空地。最初,每块空地上都有一个人,在疏散的时候,每一秒钟每个人都可以向上下左右四个方向移动一格,当然他也可以站着不动。疏散开始后,每块空地上就没有人数限制了(也就是说每块空地可以同时站无数个人)。但是,由于门很窄,每一秒钟只能有一个人移动到门的位置,一旦移动到门的位置,就表示他已经安全撤离了。现在的问题是:如果希望所有的人安全撤离,最短需要多少时间?或者告知根本不可能。
n,m<=20
看到题目很容易想到二分答案,然后分层图网络流,每一个点都拆成很多个点,每个点向下个时间点能到的点连边,然后check一下是否能狗狗全部撤离。想了想没问题,写一发T了。
但是仔细想想,并不需要那么复杂。因为这道题每个人到每个出口的路径长度确定,所以只需要把每个出口拆点就行了,每个人向每个能到的出口,第(它能到的时间)个点连边,每个出口拆成的点向下一个连边,就行啦。
代码巨丑...
#include<iostream> #include<cstring> #include<cstdio> #include<queue> #define S 0 #define T 30000 #define INF 2000000000 using namespace std; inline int read() { int x = 0 , f = 1; char ch = getchar(); while(ch < ‘0‘ || ch > ‘9‘){ if(ch == ‘-‘) f = -1; ch = getchar();} while(ch >= ‘0‘ && ch <= ‘9‘){x = x * 10 + ch - ‘0‘;ch = getchar();} return x * f; } int id[22][22],s[405][405]; int d[T+5],q[T+5],n,m,head[T+5],c[T+5],cnt=1,tot=0,top,num=0; struct edge{int to,next,w;}e[T*200]; char st[22][22]; struct pos{int x,y;};queue<pos> qu; const int dis[4][2]={{1,0},{-1,0},{0,1},{0,-1}}; inline void ins(int f,int t,int w){ e[++cnt]=(edge){t,head[f],w};head[f]=cnt; e[++cnt]=(edge){f,head[t],0};head[t]=cnt; } int dfs(int x,int f) { if(x==T)return f; int used=0; for(int&i=c[x];i;i=e[i].next) if(e[i].w&&d[e[i].to]==d[x]+1) { int w=dfs(e[i].to,min(f-used,e[i].w)); used+=w;e[i].w-=w;e[i^1].w+=w; if(used==f)return f; } return d[x]=-1,used; } bool bfs() { int i,j;memset(d,0,sizeof(d)); for(d[q[top=i=1]=S]=1;i<=top;i++) for(int j=c[q[i]]=head[q[i]];j;j=e[j].next) if(e[j].w&&!d[e[j].to]) d[q[++top]=e[j].to]=d[q[i]]+1; return d[T]; } void build(int x) { cnt=1;memset(head,0,sizeof(head)); for(int i=1;i<=num;i++) { for(int k=1;k<=x;k++) ins((k-1)*num+i,T,1); for(int k=1;k<x;k++) ins((k-1)*num+i,k*num+i,INF); } for(int i=num+1;i<=tot;i++) { ins(S,num*x+i,1); for(int j=1;j<=num;j++) if(s[i][j]<=x) ins(num*x+i,(s[i][j]-1)*num+j,INF); } } void getdis(int x,int y) { int now=id[x][y];qu.push((pos){x,y}); s[now][now]=0; while(!qu.empty()) { pos th=qu.front();qu.pop(); for(int i=0;i<4;i++) { int xx=th.x+dis[i][0],yy=th.y+dis[i][1]; if(xx<1||yy<1||xx>n||yy>m||s[xx][yy]==‘X‘) continue; if(s[now][id[th.x][th.y]]+1<s[now][id[xx][yy]]) { s[now][id[xx][yy]]=s[now][id[th.x][th.y]]+1; if(st[xx][yy]==‘.‘)qu.push((pos){xx,yy}); } } } } int main() { n=read();m=read(); for(int i=1;i<=n;i++) scanf("%s",st[i]+1); memset(s,127,sizeof(s)); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) if(st[i][j]==‘D‘)id[i][j]=++num; tot=num; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) if(st[i][j]==‘.‘) id[i][j]=++tot; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) if(st[i][j]==‘.‘) getdis(i,j); int l=1,r=324,mid,ans=-1; while(l<=r) { mid=l+r>>1;build(mid); int sum=0; while(bfs())sum+=dfs(S,INF); if(sum==tot-num)ans=mid,r=mid-1; else l=mid+1; } if(ans==-1)return 0*puts("impossible"); printf("%d\n",ans); return 0; }
以上是关于[bzoj1189] [HNOI2007]紧急疏散evacuate的主要内容,如果未能解决你的问题,请参考以下文章
BZOJ 1189[HNOI2007]紧急疏散evacuate
[bzoj1189] [HNOI2007]紧急疏散evacuate
BZOJ1189[HNOI2007]紧急疏散evacuate 动态加边网络流
BZOJ 1189 [HNOI2007]紧急疏散evacuate