1189. [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

这个题……有点像跳舞那个题emmmm……
答案肯定是满足单调性的,所以我们可以枚举
(可以和跳舞那个题一样二分,不过二分就要每次重新添加边,太麻烦)
先判断impossible,BFS判断就行。
建图:超级源点-人-门-超级汇点
枚举秒数,每一秒就在门和超级汇点间连一条容量1的边,意味着当前秒这个门可以多出一个人了
若某个人到某个门耗费的时间为当前秒数,就在人和门间连一条容量为1的边
之后跑一边最大流,若最大流为人数的话就说明人可以全跑出去了
PS每次跑最大流的时候之前的Ans不能清零emmm

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#define MAXM (100000+10)
#define MAXN (1010+10)
using namespace std;
struct node
{
    int Flow;
    int next;
    int to;
}edge[MAXM*2];
int Depth[MAXN],Q[MAXN];
int head[MAXN],num_edge;
int n,m,s,e=999,d,INF;
int a[MAXN][MAXN];
int num[MAXN][MAXN];
int dis[MAXN][MAXN];
int PEOPLE[MAXN],P_sum;
int DOOR[MAXN],D_sum;
int dx[5]={0,1,-1,0,0},dy[5]={0,0,0,1,-1};
int q[1005][3];
int Ans;
bool used[505][505];
char ch[1005];

void add(int u,int v,int l)
{
    edge[++num_edge].to=v;
    edge[num_edge].Flow=l;
    edge[num_edge].next=head[u];
    head[u]=num_edge;
}

bool Bfs(int s,int e)
{
    int Head=0,Tail=1;
    memset(Depth,0,sizeof(Depth));
    Depth[s]=1;
    Q[1]=s;
    while (Head<Tail)
    {
        int x=Q[++Head];
        for (int i=head[x];i!=0;i=edge[i].next)
            if (!Depth[edge[i].to] && edge[i].Flow>0)
            {
                Depth[edge[i].to]=Depth[x]+1;
                Q[++Tail]=edge[i].to;
            }
    }
    if (Depth[e]>0) return true;
    return false;
}

int Dfs(int x,int low)
{
    int Min,f=0;
    if (x==e || low==0)
        return low;
    for (int i=head[x];i!=0;i=edge[i].next)
        if (edge[i].Flow>0 && Depth[edge[i].to]==Depth[x]+1 && (Min=Dfs(edge[i].to , min(low,edge[i].Flow) )))
        {
            edge[i].Flow-=Min;
            edge[((i-1)^1)+1].Flow+=Min;
            f+=Min;
            low-=Min;
        }
    return f;
}

int Dinic(int s,int e)
{
//    int Ans=0;
    while (Bfs(s,e))
            Ans+=Dfs(s,0x7fffffff);
    return Ans;
}

void DISTANCE(int x,int y)
{
	int Head=0,Tail=1;
	memset(used,false,sizeof(used));
	q[1][1]=x;
	q[1][2]=y;
	used[x][y]=true;
	while (Head<Tail)
	{
		++Head;
		for (int i=1;i<=4;++i)
		{
			int xx=q[Head][1]+dx[i];
			int yy=q[Head][2]+dy[i];
			if (!used[xx][yy] && a[xx][yy])
			{
				used[xx][yy]=true;
				dis[num[x][y]][num[xx][yy]]=dis[num[x][y]][num[q[Head][1]][q[Head][2]]]+1;
				q[++Tail][1]=xx;
				q[Tail][2]=yy;
			}
		}
	}
}

int main()
{
	memset(&INF,0x7f,sizeof(INF));
	int n,m,cnt=0;
	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]==‘X‘)
				continue;
			num[i][j]=++cnt;
			if (ch[j-1]==‘.‘)
			{
				a[i][j]=1;
				PEOPLE[++P_sum]=num[i][j];
			}
			else
			{
				a[i][j]=2;
				DOOR[++D_sum]=num[i][j];
			}
		}
	}
	for (int i=1;i<=n;++i)
		for (int j=1;j<=m;++j)
			if (a[i][j])
				DISTANCE(i,j);
	for (int i=1;i<=P_sum;++i)
	{
		bool flag=false;
		for (int j=1;j<=D_sum;++j)
			if (dis[PEOPLE[i]][DOOR[j]]!=0)
			{
				flag=true;
				break;
			}
		if (!flag)
		{
			printf("impossible\n");
			return 0;
		}
	}
	for (int i=1;i<=P_sum;++i)
	{
		add(0,PEOPLE[i],1);
		add(PEOPLE[i],0,0);
	}
	for (int i=1;i<=99999999;++i)
	{
		for (int j=1;j<=D_sum;++j)
		{
			add(DOOR[j],999,1);
			add(999,DOOR[j],0);
		}
		for (int j=1;j<=P_sum;++j)
			for (int k=1;k<=D_sum;++k)
				if (dis[PEOPLE[j]][DOOR[k]]==i)
				{
					add(PEOPLE[j],DOOR[k],1);
					add(DOOR[k],PEOPLE[j],0);
				}
		if (Dinic(0,999)==P_sum)
		{
			printf("%d",i);
			return 0;
		}
	}
}

原文地址:https://www.cnblogs.com/refun/p/8678685.html

时间: 2024-08-28 21:13:41

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

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

BZOJ 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

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',那么表示这是一扇门,人们可以从这儿撤出房间.已知门一定在房间的边界上,并且

bzoj千题计划132:bzoj1189: [HNOI2007]紧急疏散evacuate

http://www.lydsy.com/JudgeOnline/problem.php?id=1189 二分答案 源点向人连边,流量为1 门拆为mid个点,同一个门的第j个点向第j+1个点连边,流量为inf 若第i个人第k秒到达第j个门,第i个人向第j个门拆出的第k个点连边,流量为1 所有门向汇点连边,流量为1 用ISAP写的,真快,也真TM长 #include<queue> #include<cstdio> #include<algorithm> #include&

AC日记——[HNOI2007]紧急疏散evacuate bzoj 1189

[HNOI2007]紧急疏散evacuate 思路: 处理每个人到门的最短路: 然后二分答案: s向人连边流量1: 人向门拆分后的点连边流量1(拆成400,前一个点连当前点流量INF): 然后门向t连边流量二分的答案: 如果最后流量等于人的个数,则true: 来,上代码: #include <queue> #include <cstdio> #include <cstring> #include <iostream> #include <algorit

【BZOJ1189】[HNOI2007]紧急疏散evacuate 动态加边网络流

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

[HNOI2007]紧急疏散EVACUATE (湖南2007年省选)

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