zoukankan      html  css  js  c++  java
  • 最大流 紧急疏散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<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);
    }


  • 相关阅读:
    Jquery中的bind()方法绑定事件总结
    composer常用命令
    Activity四种启动模式
    谷歌搜索技巧
    关于Android studio Haxm加速器安装
    关于Ping和Tracert命令原理详解
    皮尔逊相关系数
    head标签
    wireshark抓包
    数据结构与算法自学系列之动态规划(一)
  • 原文地址:https://www.cnblogs.com/QTY2001/p/7632766.html
Copyright © 2011-2022 走看看