最大流 紧急疏散evacuate

 

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
#include
#include
#include
#include
#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 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);
}


你可能感兴趣的:(网络流)