zoukankan      html  css  js  c++  java
  • bzoj1189 [HNOI2007]紧急疏散evacuate

    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

    Sample Output

    3

    今天去省冬被暴虐而归……本想刷刷水题,结果又被水题虐了……调了半天加边的时候手滑++cnt写成+cnt结果调了一晚上

    就是二分+网络流。先预处理所有门到空地的距离。然后每次二分一个最短时间+dinic判定。S向空地连边,空地向能到的门连边,门再向T连边。最后判断是否流量==空地数

    #include<cstdio>
    #include<cstring>
    #define S 0
    #define T 1000
    #define inf 0x7fffffff
    const int mx[4]={-1,0,1,0};
    const int my[4]={0,1,0,-1};
    int cnt=1,ans=-1,sum,tot;
    struct point{
    	int x,y;
    }d[401];
    struct queue{
    	int x,y,t;
    }q[1001];
    struct edge{
    	int from,to,next,v;
    }e[100000];
    int n,m,doors,l,r;
    char ch[100];
    int head[10001];
    int h[10001];
    int dist[401][21][21];
    bool map[21][21];
    bool flag[21][21];
    inline int min(int a,int b)
    {return a<b?a:b;}
    inline void ins(int u,int v,int w)
    {
    	e[++cnt].v=w;
    	e[cnt].from=u;
    	e[cnt].to=v;
    	e[cnt].next=head[u];
    	head[u]=cnt;
    }
    inline void insert(int u,int v,int w)
    {
    	ins(u,v,w);
    	ins(v,u,0);
    }
    inline void search(int k)
    {
    	memset(q,0,sizeof(q));
    	memset(flag,0,sizeof(flag));
    	int t=0,w=1;
    	q[1].x=d[k].x;
    	q[1].y=d[k].y;
    	flag[q[1].x][q[1].y]=1;
    	while (t<w)
    	{
    		int nx=q[++t].x,ny=q[t].y,nt=q[t].t;
    		for (int i=0;i<4;i++)
    		  if (map[nx+mx[i]][ny+my[i]]&&!flag[nx+mx[i]][ny+my[i]])
    		  {
    		  	dist[k][nx+mx[i]][ny+my[i]]=nt+1;
    		  	flag[nx+mx[i]][ny+my[i]]=1;
    		  	q[++w].x=nx+mx[i];
    		  	q[w].y=ny+my[i];
    		  	q[w].t=nt+1;
    		  }
    	}
    }
    inline bool bfs()
    {
    	int que[10001];
    	memset(h,-1,sizeof(h));
    	int t=0,w=1;
    	h[S]=0;que[1]=S;
    	while (t<w)
    	{
    		int now=que[++t];
    		for (int i=head[now];i;i=e[i].next)
    		  if (e[i].v&&h[e[i].to]==-1)
    		  {
    		  	que[++w]=e[i].to;
    		  	h[e[i].to]=h[now]+1;
    		  }
    	}
    	if (h[T]==-1) return 0;
    	return 1;
    }
    inline int dfs(int x,int f)
    {
    	if (x==T||f==0) return f;
    	int w,used=0;
    	for (int i=head[x];i;i=e[i].next)
    	  if (e[i].v&&h[e[i].to]==h[x]+1)
    	  {
    	  	w=f-used;
    	  	w=dfs(e[i].to,min(e[i].v,w));
    	  	e[i].v-=w;
    	  	e[i^1].v+=w;
    	  	used+=w;
    	  }
    	if (!used) h[x]=-1;
    	return used; 
    }
    inline void dinic()
    {
    	while (bfs()) sum+=dfs(S,inf);
    }
    inline void buildmap(int time)
    {
    	cnt=1;sum=0;
    	memset(e,0,sizeof(e));
    	memset(head,0,sizeof(head));
    	for (int i=1;i<=n;i++)
    	  for (int j=1;j<=m;j++)
    	    if (map[i][j]) insert(S,(i-1)*m+j,1);
    	    
    	for (int i=1;i<=doors;i++)
    	  {
    	  	insert(n*m+i+1,T,time);
    	  	for (int j=1;j<=n;j++)
    	  	  for (int k=1;k<=m;k++)
    	  	    if (dist[i][j][k]<=time) insert((j-1)*m+k,n*m+i+1,time);
    	  }
    }
    inline bool jud(int k)
    {
    	buildmap(k);
    	for (int i=2;i<=cnt;i+=2)
    	dinic();
    	return sum==tot;
    }
    int main()
    {
    	scanf("%d%d",&n,&m);
    	for (int i=1;i<=n;i++)
    	{
    	  scanf("%s",ch);
    	  for(int j=1;j<=m;j++)
    	    {
    	    	if (ch[j-1]=='.')
    			{
    				map[i][j]=1;
    				tot++;
    			}
    	    	if (ch[j-1]=='D')
    	    	{
    	    		d[++doors].x=i;
    	    		d[doors].y=j;
    	    	}
    	    }
    	}
    	memset(dist,127/3,sizeof(dist));
    	for (int i=1;i<=doors;i++)search(i);
    	l=0;r=400;
    	while (l<=r)
    	{
    		int mid=(l+r)>>1;
    		if (jud(mid)){ans=mid;r=mid-1;}
    		else l=mid+1;
    	}
    	if(ans!=-1)printf("%d",ans);
    	else printf("impossible");
    	return 0;
    }


    ——by zhber,转载请注明来源
  • 相关阅读:
    bzoj 4548 小奇的糖果
    CF1151F Sonya and Informatics
    loj 2392「JOISC 2017 Day 1」烟花棒
    loj 2336「JOI 2017 Final」绳
    luogu P3620 [APIO/CTSC 2007]数据备份
    bzoj 4771 七彩树
    CF765F Souvenirs
    bzoj 3145 [Feyat cup 1.5]Str
    luogu P4482 [BJWC2018]Border 的四种求法
    第五章例题
  • 原文地址:https://www.cnblogs.com/zhber/p/4036061.html
Copyright © 2011-2022 走看看