题目描述

发生了火警,所有人员需要紧急疏散!假设每个房间是一个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


写题解之前先把一些该说的说了。

1.经过小号交题测试,此题网上题解有一半是WA的

2.另一半A的,绝大多数写的是二分

3.事实证明,动态加边效率和二分不会差很多,而且相比二分代码非常短

题解

BFS最短路+动态加边网络流

题目中描述“每一秒钟只能有一个人移动到门的位置”,我们其实不用这样去看,可以看成很多人可以同时站在门的位置,但是每秒最多只能有1个人从门的位置逃出。

这样就提供了一个思路:先用最短的时间走到门的位置,再考虑逃出情况。

所以需要求一下每个空地到每个门的最短路,由于边权为1,可以使用BFS求最短路。

这里有一个坑点:存在一种门后边还有门的情况(例:

4 4
DXXD
X..D
X..X
DXXX

ans=4)

其中发现按照上面的思路,一个人到门的位置,另一个人从该门出去,答案应该为3。(错在这里卡了1天QAQ)

问题就出在门后之门。

错误原因就在于走了门后之门。而事实上,门后之门是没有用的,因为按照正常思路,通过门后之门需要先经过前门,而经过前门就可以出去,无需下一步。

所以在BFS时只能走空地,不能走门。

这是此题难点之一。

然后加边:s->空地,容量为1;空地->门的第t层,容量为1,其中t=空地到门的距离。

枚举时间t,动态加边门的第t-1层->门的第t层,容量为inf;门的第t层->t,容量为1。

判断满流即可。

时间上界是n*m,因此只需要枚举到n*m就行。

代码很丑。。。pos(i,j)表示点(i,j)对应的编号,loc(i,j)表示第i个门的第j层对应的编号。

#include <cstdio>
#include <cstring>
#include <queue>
#define inf 0x3f3f3f3f
#define pos(i , j) (i - 1) * m + j
#define loc(i , j) (j == 0 ? pd[i] : n * m + 1 + (j - 1) * tot + i)
using namespace std;
queue<int> q;
int n , m , map[600] , len[600][100] , pd[100] , tot;
int head[200000] , to[2000000] , val[2000000] , next[2000000] , cnt = 1 , s , t , dis[200000];
char str[25];
void search(int k)
{
int x , i;
for(i = 1 ; i <= n * m ; i ++ )
len[i][k] = -1;
while(!q.empty()) q.pop();
len[pd[k]][k] = 0 , q.push(pd[k]);
while(!q.empty())
{
x = q.front() , q.pop();
if(x > m && map[x - m] == 1 && len[x - m][k] == -1) len[x - m][k] = len[x][k] + 1 , q.push(x - m);
if(x <= m * (n - 1) && map[x + m] == 1 && len[x + m][k] == -1) len[x + m][k] = len[x][k] + 1 , q.push(x + m);
if(x % m != 1 && map[x - 1] == 1 && len[x - 1][k] == -1) len[x - 1][k] = len[x][k] + 1 , q.push(x - 1);
if(x % m != 0 && map[x + 1] == 1 && len[x + 1][k] == -1) len[x + 1][k] = len[x][k] + 1 , q.push(x + 1);
}
}
void add(int x , int y , int z)
{
to[++cnt] = y , val[cnt] = z , next[cnt] = head[x] , head[x] = cnt;
to[++cnt] = x , val[cnt] = 0 , next[cnt] = head[y] , head[y] = cnt;
}
bool bfs()
{
int x , i;
memset(dis , 0 , sizeof(dis));
while(!q.empty()) q.pop();
dis[s] = 1 , q.push(s);
while(!q.empty())
{
x = q.front() , q.pop();
for(i = head[x] ; i ; i = next[i])
{
if(val[i] && !dis[to[i]])
{
dis[to[i]] = dis[x] + 1;
if(to[i] == t) return 1;
q.push(to[i]);
}
}
}
return 0;
}
int dinic(int x , int low)
{
if(x == t) return low;
int temp = low , i , k;
for(i = head[x] ; i ; i = next[i])
{
if(val[i] && dis[to[i]] == dis[x] + 1)
{
k = dinic(to[i] , min(temp , val[i]));
if(!k) dis[to[i]] = 0;
val[i] -= k , val[i ^ 1] += k;
if(!(temp -= k)) break;
}
}
return low - temp;
}
int main()
{
int i , j , sum = 0;
scanf("%d%d" , &n , &m) , s = 0 , t = n * m + 1;
for(i = 1 ; i <= n ; i ++ )
{
scanf("%s" , str + 1);
for(j = 1 ; j <= m ; j ++ )
{
if(str[j] == 'D') pd[++tot] = pos(i , j) , map[pos(i , j)] = 2;
else if(str[j] == '.') add(s , pos(i , j) , 1) , map[pos(i , j)] = 1 , sum ++ ;
}
}
for(i = 1 ; i <= tot ; i ++ ) search(i);
for(i = 1 ; i <= n * m ; i ++ )
if(map[i] == 1)
for(j = 1 ; j <= tot ; j ++ )
if(len[i][j] != -1)
add(i , loc(j , len[i][j]) , 1);
for(i = 1 ; i <= 2 * n * m ; i ++ )
{
for(j = 1 ; j <= tot ; j ++ ) add(loc(j , i - 1) , loc(j , i) , inf) , add(loc(j , i) , t , 1);
while(bfs()) sum -= dinic(s , inf);
if(!sum)
{
printf("%d\n" , i);
return 0;
}
}
printf("impossible\n");
return 0;
}

【bzoj1189】[HNOI2007]紧急疏散evacuate BFS最短路+动态加边网络流的更多相关文章

  1. Bzoj1189 [HNOI2007]紧急疏散evacuate

    1189: [HNOI2007]紧急疏散evacuate Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 2293  Solved: 715 Descr ...

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

    1189: [HNOI2007]紧急疏散evacuate Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1132  Solved: 412[Submi ...

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

    我们可以BFS出每个出口到每个人的最短距离, 然后二分答案, 假设当前答案为m, 把一个出口拆成m个表示m个时间, 点u到出口v的距离为d, 那么u->v的[d, m]所有点连边, 然后跑匈牙利 ...

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

    http://www.lydsy.com/JudgeOnline/problem.php?id=1189 二分答案 源点向人连边,流量为1 门拆为mid个点,同一个门的第j个点向第j+1个点连边,流量 ...

  5. BZOJ1189: [HNOI2007]紧急疏散evacuate(二分答案,最大流)

    Description 发生了火警,所有人员需要紧急疏散!假设每个房间是一个N M的矩形区域.每个格子如果是'.',那么表示这是一 块空地:如果是'X',那么表示这是一面墙,如果是'D',那么表示这是 ...

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

    [法一]枚举Time(0~N*M): S->'.'(1); 'D'->T(Time); '.'->'D'(dis(用BFS预处理,注意一旦到达'D',BFS就不能继续扩展了,注意di ...

  7. BZOJ1189 [HNOI2007]紧急疏散evacuate 【二分 + 网络流】

    题目 发生了火警,所有人员需要紧急疏散!假设每个房间是一个N M的矩形区域.每个格子如果是'.',那么表示这是一 块空地:如果是'X',那么表示这是一面墙,如果是'D',那么表示这是一扇门,人们可以从 ...

  8. BZOJ1189:[HNOI2007]紧急疏散EVACUATE(最大流,枚举)

    Description 发生了火警,所有人员需要紧急疏散!假设每个房间是一个N M的矩形区域.每个格子如果是'.',那么表示这是一 块空地:如果是'X',那么表示这是一面墙,如果是'D',那么表示这是 ...

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

    [BZOJ1189][HNOI2007]紧急疏散evacuate Description 发生了火警,所有人员需要紧急疏散!假设每个房间是一个N M的矩形区域.每个格子如果是'.',那么表示这是一块空 ...

随机推荐

  1. 【UVA10652】Board Wrapping(求凸包面积)

    点此看题面 大致题意: 告诉你若干个矩形的重心坐标.长.宽和相对\(y\)轴的偏转角度,求矩形面积和与能围住这些矩形的最小凸包面积之比. 矩形面积和 这应该是比较好求的吧. 已经给了你长和宽,直接乘起 ...

  2. 我的Linux学习之路的感悟

    首先要跟大家说声抱歉,这么久一直没有更新,有负大家对我的期望. 半年的Linux运维的学习到目前已工作一个月零9天,这一路走来的艰辛和挣扎只有自己最清楚. 首先要感谢公司的同事的宽容接纳和耐心指点.感 ...

  3. shiro学习记录(二)

    1 在项目中应用shiro框架进行认证 第一步:引入shiro框架相关的jar <!-- 引入shiro框架的依赖 --> <dependency> <groupId&g ...

  4. Oracle 数据处理

    1. 对维度按照度量值的排名进行统计得分,第一名100分,第二名99分,第三名98……可以先进行排名,然后用 得分值+1,减去排名既是所得分数. -- 建表 create table province ...

  5. SVN不显示状态图标

    1,输入win+R,输入regedit,调出注册表信息 2,按下Ctrl+F,在注册表里搜索“ShellIconOverlayIdentifiers” 3,将TortoiseAdded.Tortois ...

  6. BZOJ2023: [Usaco2005 Nov]Ant Counting 数蚂蚁(dp)

    题意 题目描述的很清楚...  有一天,贝茜无聊地坐在蚂蚁洞前看蚂蚁们进进出出地搬运食物.很快贝茜发现有些蚂蚁长得几乎一模一样,于是她认为那些蚂蚁是兄弟,也就是说它们是同一个家族里的成员.她也发现整个 ...

  7. [BZOJ] 2044: 三维导弹拦截

    排序去掉一维,剩下两维可以直接\(O(n^2)\)做,也可以用二维树状数组(但是不方便建边),解决第一问 第二问,按转移顺序连边,建出DAG,求最小不可重链覆盖即可 #include<algor ...

  8. MySQL详细安装过程

    目录 一.概述 二.MySQL安装 三.安装成功验证 四.NavicatforMySQL下载及使用 一.概述 MySQL版本:5.7.17 下载地址:http://rj.baidu.com/soft/ ...

  9. 破解studio 3T

    方法一: 打开注册表:regedit 计算机\HKEY_CURRENT_USER\Software\JavaSoft\Prefs\3t\mongochef\enterprise 将里面得数据清零,又是 ...

  10. PHP switch问题

    $a = 0; switch($a){ case $a > 7: echo 234; break; case $a > 2: echo 4556; break; default: echo ...