1189: [HNOI2007]紧急疏散evacuate
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1637 Solved: 557
[ Submit][ Status][ Discuss]
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
解题思路:二分答案,然后判断。对每扇门拆成400个以时间为依据的点。然后最大流。
- #include <queue>
- #include <cstdio>
- #include <cstring>
- #include <iostream>
- #include <algorithm>
- #define P 25
- #define N 500
- #define M 300000
- #define R 500
- #define inf 0x3f3f3f3f
- using namespace std;
- const int dx[]={0,0,1,-1};
- const int dy[]={1,-1,0,0};
- struct KSD
- {
- int v,len,next;
- int flow;
- void init(){len=flow;}
- }e[M];
- int head[50000],cnt;
- inline void add(int u,int v,int len)
- {
- e[++cnt].v=v;
- e[cnt].len=e[cnt].flow=len;
- e[cnt].next=head[u];
- head[u]=cnt;
- }
- inline void Add(int u,int v,int len){add(u,v,len),add(v,u,0);}
- int s,t,d[50000];
- queue<int>q;
- bool bfs()
- {
- memset(d,0,sizeof d);
- while(!q.empty())q.pop();
- int i,u,v;
- q.push(s),d[s]=1;
- while(!q.empty())
- {
- u=q.front(),q.pop();
- for(i=head[u];i;i=e[i].next)
- {
- if(!d[v=e[i].v]&&e[i].len)
- {
- d[v]=d[u]+1;
- if(v==t)return 1;
- q.push(v);
- }
- }
- }
- return 0;
- }
- int dinic(int x,int flow)
- {
- if(x==t)return flow;
- int remain=flow,i,v,k;
- for(i=head[x];i&&remain;i=e[i].next)
- {
- if(e[i].len&&d[v=e[i].v]==d[x]+1)
- {
- k=dinic(v,min(remain,e[i].len));
- if(!k)d[v]=0;
- e[i].len-=k,e[i^1].len+=k;
- remain-=k;
- }
- }
- return flow-remain;
- }
- int blank[N],blanks;
- int door[N],doors;
- int point[N][R+5],rec[N][R+5];
- bool is_door[N];
- void build(int mid)
- {
- int i,j;
- for(i=2;i<=cnt;i++)e[i].init();
- for(i=1;i<=doors;i++)for(j=mid+1;j<=R;j++)e[rec[i][j]].len=0;
- return ;
- }
- int n,m,id[P][P];
- int map[N][N];
- char src[P][P];
- void Build(int &l,int &r)
- {
- int i,j,k;
- int tx,ty;
- scanf("%d%d",&n,&m);
- for(i=1;i<=n;i++)scanf("%s",src[i]+1);
- for(i=1;i<=n;i++)for(j=1;j<=m;j++)
- {
- if(src[i][j]=='.')blank[++blanks]=id[i][j]=++cnt;
- else if(src[i][j]=='D')
- {
- door[++doors]=id[i][j]=++cnt;
- is_door[cnt]=true;
- }
- }
- memset(map,0x3f,sizeof map);
- for(i=1;i<=cnt;i++)map[i][i]=0;
- for(i=1;i<=n;i++)for(j=1;j<=m;j++)if(id[i][j])
- for(k=0;k<4;k++)if(id[tx=i+dx[k]][ty=j+dy[k]])
- map[id[i][j]][id[tx][ty]]=1;
- for(k=1;k<=cnt;k++)
- {
- if(is_door[k])continue;
- for(i=1;i<=cnt;i++)for(j=1;j<=cnt;j++)map[i][j]=min(map[i][j],map[i][k]+map[k][j]);
- }
- cnt=blanks;
- for(i=1;i<=doors;i++)for(j=1;j<=R;j++)point[i][j]=++cnt;
- s=0,t=cnt+1,cnt=1;
- for(i=1;i<=blanks;i++)
- {
- Add(s,i,1); // 500
- int res=inf;
- for(j=1;j<=doors;j++)
- res=min(res,map[blank[i]][door[j]]);
- l=max(l,res);
- }
- for(i=1;i<=doors;i++)
- {
- int I=door[i],J;
- for(j=1;j<=blanks;j++)if(map[I][J=blank[j]]<inf)
- Add(j,point[i][map[I][J]],1);
- }
- for(i=1;i<=doors;i++)for(j=1;j<R;j++)Add(point[i][j],point[i][j+1],inf);
- for(i=1;i<=doors;i++)for(j=1;j<=R;j++) // 80*500
- {
- Add(point[i][j],t,1);
- rec[i][j]=cnt-1;
- }
- return ;
- }
- bool check(int mid)
- {
- build(mid);
- int maxflow=0;
- while(bfs())maxflow+=dinic(s,inf);
- if(maxflow==blanks)return 1;
- return 0;
- }
- int main()
- {
- int l=0,r=R,mid,ans=inf;
- Build(l,r);
- while(l<=r)
- {
- if(r-l<=3)
- {
- for(int i=l;i<=r;i++)if(check(i)){ans=i;break;}
- break;
- }
- mid=l+r>>1;
- if(check(mid))r=mid;
- else l=mid+1;
- }
- if(ans==inf)puts("impossible");
- else printf("%d\n",ans);
- return 0;
- }