【枚举】【二分答案】【分块答案】【BFS】【最大流】【Dinic】bzoj1189 [HNOI2007]紧急疏散evacuate

【法一】枚举Time(0~N*M):

S->‘.‘(1);

‘D‘->T(Time);

‘.‘->‘D‘(dis(用BFS预处理,注意一旦到达‘D‘,BFS就不能继续扩展了,注意dis的初值0x7f)<=Time ? 1 : 0);

判断是否满流;

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
#define INF 2147483647
#define MAXN 411
#define MAXM 350001
int v[MAXM],cap[MAXM],en,first[MAXN],next[MAXM];
int d[MAXN],cur[MAXN];
queue<int>q;
int n,S,T,N,M;
void Init_Dinic(){memset(first,-1,sizeof(first)); en=0; S=0; n=N*M+2; T=N*M+1;}
void AddEdge(const int &U,const int &V,const int &W)
{v[en]=V; cap[en]=W; next[en]=first[U]; first[U]=en++;
v[en]=U; next[en]=first[V]; first[V]=en++;}
bool bfs()
{
    memset(d,-1,sizeof(d)); q.push(S); d[S]=0;
    while(!q.empty())
      {
        int U=q.front(); q.pop();
        for(int i=first[U];i!=-1;i=next[i])
          if(d[v[i]]==-1 && cap[i])
            {
              d[v[i]]=d[U]+1;
              q.push(v[i]);
            }
      }
    return d[T]!=-1;
}
int dfs(int U,int a)
{
    if(U==T || !a) return a;
    int Flow=0,f;
    for(int &i=cur[U];i!=-1;i=next[i])
      if(d[U]+1==d[v[i]] && (f=dfs(v[i],min(a,cap[i]))))
        {
          cap[i]-=f; cap[i^1]+=f;
          Flow+=f; a-=f; if(!a) break;
        }
    if(!Flow) d[U]=-1;
    return Flow;
}
int max_flow()
{
    int Flow=0,tmp=0;
    while(bfs())
      {
        memcpy(cur,first,(n+5)*sizeof(int));
        while(tmp=dfs(S,INF)) Flow+=tmp;
      }
    return Flow;
}
int dis[22*22][22*22];
bool vis[22][22];
char map[22][22];
int num[22][22];
struct Node
{
	int x,y,d;
	Node(const int &a,const int &b,const int &c)
	{x=a;y=b;d=c;}
	Node(){}
};
const int dx[]={0,1,0,-1},dy[]={1,0,-1,0};
int man[22*22],door[22*22],summ,sumd;
int main()
{
	scanf("%d%d",&N,&M);
	for(int i=1;i<=N;++i) scanf("%s",map[i]+1);
	for(int i=1;i<=N;++i)
	  for(int j=1;j<=M;++j)
	    {
	      num[i][j]=++en;
	      if(map[i][j]==‘.‘) man[++summ]=en;
	      else if(map[i][j]==‘D‘) door[++sumd]=en;
	    }
	memset(dis,0x7f,sizeof(dis));
    queue<Node>q;
	for(int i=1;i<=N;++i)
	  for(int j=1;j<=M;++j)
	    if(map[i][j]==‘.‘)
	      {
	      	memset(vis,0,sizeof(vis));
	      	q.push(Node(i,j,0));
	      	vis[i][j]=1;
	      	while(!q.empty())
	      	  {
	      	  	Node U=q.front(); q.pop();
	      	  	for(int k=0;k<4;++k)
	      	  	  {
	      	  	  	int tx=U.x+dx[k],ty=U.y+dy[k];
	      	  	  	if(tx>=1 && tx<=N && ty>=1 && ty<=M && map[tx][ty]!=‘X‘ && (!vis[tx][ty]))
	      	  	  	  {
	      	  	  	  	if(map[tx][ty]==‘D‘)
						  {
						  	dis[num[i][j]][num[tx][ty]]=U.d+1;
						  	continue;//注意:到了门立刻离开,不能继续。
						  }
	      	  	  	  	vis[tx][ty]=1;
						q.push(Node(tx,ty,U.d+1));
	      	  	  	  }
	      	  	  }
	      	  }
	      }
	for(int Time=0;Time<=N*M;++Time)
	  {
	  	Init_Dinic();
	  	for(int i=1;i<=summ;++i) AddEdge(S,man[i],1);
	  	for(int i=1;i<=sumd;++i) AddEdge(door[i],T,Time);
	  	for(int i=1;i<=summ;++i)
	  	  for(int j=1;j<=sumd;++j)
	  	    if(dis[man[i]][door[j]]<=Time)
	  	      AddEdge(man[i],door[j],1);
	  	if(max_flow()==summ)
	  	  {
	  	  	printf("%d\n",Time);
	  	  	return 0;
	  	  }
	  }
	puts("impossible");
	return 0;
}

  

【法二】可以二分答案,但是边界总是挂……分块答案。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
using namespace std;
#define INF 2147483647
#define MAXN 411
#define MAXM 350001
int v[MAXM],cap[MAXM],en,first[MAXN],next[MAXM];
int d[MAXN],cur[MAXN];
queue<int>q;
int n,S,T,N,M;
void Init_Dinic(){memset(first,-1,sizeof(first)); en=0; S=0; n=N*M+2; T=N*M+1;}
void AddEdge(const int &U,const int &V,const int &W)
{v[en]=V; cap[en]=W; next[en]=first[U]; first[U]=en++;
v[en]=U; next[en]=first[V]; first[V]=en++;}
bool bfs()
{
    memset(d,-1,sizeof(d)); q.push(S); d[S]=0;
    while(!q.empty())
      {
        int U=q.front(); q.pop();
        for(int i=first[U];i!=-1;i=next[i])
          if(d[v[i]]==-1 && cap[i])
            {
              d[v[i]]=d[U]+1;
              q.push(v[i]);
            }
      }
    return d[T]!=-1;
}
int dfs(int U,int a)
{
    if(U==T || !a) return a;
    int Flow=0,f;
    for(int &i=cur[U];i!=-1;i=next[i])
      if(d[U]+1==d[v[i]] && (f=dfs(v[i],min(a,cap[i]))))
        {
          cap[i]-=f; cap[i^1]+=f;
          Flow+=f; a-=f; if(!a) break;
        }
    if(!Flow) d[U]=-1;
    return Flow;
}
int max_flow()
{
    int Flow=0,tmp=0;
    while(bfs())
      {
        memcpy(cur,first,(n+5)*sizeof(int));
        while(tmp=dfs(S,INF)) Flow+=tmp;
      }
    return Flow;
}
int dis[22*22][22*22];
bool vis[22][22];
char map[22][22];
int num[22][22];
struct Node
{
	int x,y,d;
	Node(const int &a,const int &b,const int &c)
	{x=a;y=b;d=c;}
	Node(){}
};
const int dx[]={0,1,0,-1},dy[]={1,0,-1,0};
int man[22*22],door[22*22],summ,sumd;
void Rebuild(const int &Time)
{
	Init_Dinic();
	for(int i=1;i<=summ;++i) AddEdge(S,man[i],1);
	for(int i=1;i<=sumd;++i) AddEdge(door[i],T,Time);
	for(int i=1;i<=summ;++i)
	  for(int j=1;j<=sumd;++j)
	  	if(dis[man[i]][door[j]]<=Time)
	  	  AddEdge(man[i],door[j],1);
}
int main()
{
	scanf("%d%d",&N,&M);
	for(int i=1;i<=N;++i) scanf("%s",map[i]+1);
	for(int i=1;i<=N;++i)
	  for(int j=1;j<=M;++j)
	    {
	      num[i][j]=++en;
	      if(map[i][j]==‘.‘) man[++summ]=en;
	      else if(map[i][j]==‘D‘) door[++sumd]=en;
	    }
	memset(dis,0x7f,sizeof(dis));
    queue<Node>q;
	for(int i=1;i<=N;++i)
	  for(int j=1;j<=M;++j)
	    if(map[i][j]==‘.‘)
	      {
	      	memset(vis,0,sizeof(vis));
	      	q.push(Node(i,j,0));
	      	vis[i][j]=1;
	      	while(!q.empty())
	      	  {
	      	  	Node U=q.front(); q.pop();
	      	  	for(int k=0;k<4;++k)
	      	  	  {
	      	  	  	int tx=U.x+dx[k],ty=U.y+dy[k];
	      	  	  	if(tx>=1 && tx<=N && ty>=1 && ty<=M && map[tx][ty]!=‘X‘ && (!vis[tx][ty]))
	      	  	  	  {
	      	  	  	  	if(map[tx][ty]==‘D‘)
						  {
						  	dis[num[i][j]][num[tx][ty]]=U.d+1;
						  	continue;//注意:到了门立刻离开,不能继续。
						  }
	      	  	  	  	vis[tx][ty]=1;
						q.push(Node(tx,ty,U.d+1));
	      	  	  	  }
	      	  	  }
	      	  }
	      }
	int sz=sqrt(N*M),last=0;
	for(int Time=0;last<=N*M;Time+=sz)
	  {
	  	Rebuild(Time);
	  	if(max_flow()>=summ)
	  	  {
	  	  	for(int i=last+1;i<=Time;++i)
	  	  	  {
	  	  	  	Rebuild(i);
	  	  	  	if(max_flow()==summ)
	  	  	  	{printf("%d\n",i); return 0;}
	  	  	  }
	  	  	return 0;
	  	  } last=Time;
	  }
	puts("impossible");
	return 0;
}

  

时间: 2024-10-01 18:06:24

【枚举】【二分答案】【分块答案】【BFS】【最大流】【Dinic】bzoj1189 [HNOI2007]紧急疏散evacuate的相关文章

BZOJ1189: [HNOI2007]紧急疏散evacuate 二分+最大流

1189: [HNOI2007]紧急疏散evacuate Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1132  Solved: 412[Submit][Status][Discuss] Description 发生了火警,所有人员需要紧急疏散!假设每个房间是一个N M的矩形区域.每个格子如果是'.',那么表示这是一块空地:如果是'X',那么表示这是一面墙,如果是'D',那么表示这是一扇门,人们可以从这儿撤出房间.已知门一定在房间的边界上,并且

BZOJ1189 HNOI2007 紧急疏散evacuate 网络流+BFS+二分法

题意:一个N M的矩形区域.格子如果是'.',那么表示这是一块空地:如果是'X',那么表示这是一面墙,如果是'D',那么表示这是一扇门,人们可以从这儿撤出房间.已知门一定在房间的边界上,并且边界上不会有空地.每块空地上都有一个人,在疏散的时候,每一秒钟每个人都可以向上下左右四个方向移动一格,当然他也可以站着不动.疏散开始后,每块空地上就没有人数限制.每一秒钟只能有一个人移动到门的位置,一旦移动到门的位置,就表示他已经安全撤离了.求所有的人安全撤离,最短需要多少时间 题解: 好神啊这题…… 首先我

BZOJ 1189: [HNOI2007]紧急疏散evacuate( BFS + 二分答案 + 匈牙利 )

我们可以BFS出每个出口到每个人的最短距离, 然后二分答案, 假设当前答案为m, 把一个出口拆成m个表示m个时间, 点u到出口v的距离为d, 那么u->v的[d, m]所有点连边, 然后跑匈牙利去check就行了...其实这道题挺好想但是码量还是挺大的.... ----------------------------------------------------------------------------- #include<cstdio> #include<cstring&

BZOJ 1189 HNOI2007 紧急疏散evacuate 二分答案+最大流

题目大意:给定一个m*n的地图,每个点有可能是空地.墙或者出口,每个空地初始站着一个人,每一时刻可以向周围走1格,门每一时刻只能通过一个人,求最短多少时间后所有人可以撤离 首先从每个出口出发开始广搜,得到每个空地到所有出口的距离 然后二分答案,每次建图如下: 从源点向每个空地一条流量为1的边 如果一个空地能在规定时间到达某个出口,就从这个空地出发向该出口链接一条流量为1的边 每个出口向汇点连接一条流量为时间的边 然后跑最大流验证即可 注意图有不连通的情况 所以广搜要清初值(这个没人会忘吧QAQ

1189. [HNOI2007]紧急疏散EVACUATE【最大流+枚举或二分】

Description 发生了火警,所有人员需要紧急疏散!假设每个房间是一个N M的矩形区域.每个格子如果是'.',那么表示这是一 块空地:如果是'X',那么表示这是一面墙,如果是'D',那么表示这是一扇门,人们可以从这儿撤出房间.已知门 一定在房间的边界上,并且边界上不会有空地.最初,每块空地上都有一个人,在疏散的时候,每一秒钟每个人都 可以向上下左右四个方向移动一格,当然他也可以站着不动.疏散开始后,每块空地上就没有人数限制了(也就是 说每块空地可以同时站无数个人).但是,由于门很窄,每一秒

【BZOJ】1189: [HNOI2007]紧急疏散evacuate(二分+bfs+网络流)

http://www.lydsy.com/JudgeOnline/problem.php?id=1189 表示完全不会QAQ.... 于是膜拜题解orz 二分时间........... 于是转换成判定性问题:即如何在有限时间内通过. 假设当前有t时间可供通过...那么每一个门最多能通过t个人........ 然后将所有能够到达门的点连边,容量为无限.... 然后源向每个点可行点连边..容量1.. 然后每个门向汇连边..容量为t.. 然后判断即可.... (一开始bfs写错了啊QAQ.. #inc

【分块答案】【最小割】bzoj1532 [POI2005]Kos-Dicing

引用zky的题解:http://blog.csdn.net/iamzky/article/details/39667859 每条S-T路径代表一次比赛的结果.最小割会尽量让一个人赢得最多. 因为二分总是写挂,所以写了分块答案,比暴力枚举好像快不了多少. #include<cstdio> #include<cstring> #include<algorithm> #include<queue> #include<cmath> using names

POJ 2391Ombrophobic Bovines(二分+最短路+网络流之最大流)

题目地址:http://poj.org/problem?id=2391 这个题WA了一晚上,原因是数组开小了,然后又TLE了一天,原因是数组改的过大了....不多说什么了... 思路不难,建图也不难,二分时间,然后把每个田地之间的最短距离用floyd最短路求出来.然后建立一个源点与汇点,将田地拆分成两个点,在距离之内的进行连边,要单向连边.然后将源点与田地相连,权值为每个田地的牛的数目,再把另一边的田地与汇点相连,权值为每个田地最大可避雨的牛的数目.拆开的田地之间权值可以为无穷大. 代码如下:

hdu4430之枚举+二分

Yukari's Birthday Time Limit: 12000/6000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 2549    Accepted Submission(s): 522 Problem Description Today is Yukari's n-th birthday. Ran and Chen hold a celebration party