嘟嘟嘟

看数据范围,第一反应觉得爆搜是不是能骗点分,但发现爆搜太难写了,于是就开始想想正解……

正解大概猜到了是网络流,但是怎么把时间这个条件加入到图的内容中,却困扰了我好半天,总是感觉把这种不同维度的条件整合到一块肯定得用什么很奇葩的方法,于是我就想不出来了……

看题解。

先二分时间(有道理啊,我怎么没想出来)。

然后我们可以转化一下,每一个人都已经到达了门前,不过到达的时刻不同,也就是说,对于这个人和这扇门他只能在大于等于他的到达时间的时候进去。

题中还说,一扇门一秒只能进一个人,为了把这个限制条件体现出来,我们把每一扇门拆点:对于当前二分的值mid,把每一扇门拆成mid + 1(包括0这个时刻)个点,每一个点向汇点连一条容量为1的边,然后对于一个人在哪个时候到达这个门的,就像第几时刻的点连一条容量为1的边。

还有一点,就是如果第 i 时刻人数大于1的话,那自然的剩下的人要等到 j (j > i)的时刻才能进门,为了体现这个,我们还要把每一扇门的每一个拆点 i,向 i +1连一条容量为INF的边。

建图到这里就讲完了,接下来说一下预处理。

首先我们要预处理每一个人到每一扇门的距离,而不是只到最近的门,因为虽然最近,但可能等待的时间非常长。我们可以从每一扇门开始对这个图来一次bfs,记录每一个点到这扇门的距离(我存到了一个vector中)。

然后二分重新建图的时候对于每一个点,从源点连一条容量为1的边;对于每一扇门,先按时间拆点,然后遍历自己的vector连边就行可以了。

还有一个值得注意的就是点的编号别重了,而且要确定好汇点的编号是多大:理论上最大值应该是20 * 20 + 76 * 20 * 20 = 30800, 76是最多有76扇门,但实际上我们只用开1e4就能过了。

 #include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<cctype>
#include<vector>
#include<stack>
#include<queue>
using namespace std;
#define enter puts("")
#define space putchar(' ')
#define Mem(a, x) memset(a, x, sizeof(a))
#define rg register
typedef long long ll;
typedef double db;
const int INF = 0x3f3f3f3f;
const db eps = 1e-;
const int maxn = 1e4 + ;
const int max_map = ;
inline ll read()
{
ll ans = ;
char ch = getchar(), last = ' ';
while(!isdigit(ch)) {last = ch; ch = getchar();}
while(isdigit(ch)) {ans = ans * + ch - ''; ch = getchar();}
if(last == '-') ans = -ans;
return ans;
}
inline void write(ll x)
{
if(x < ) x = -x, putchar('-');
if(x >= ) write(x / );
putchar(x % + '');
} int n, m, t, tot1 = , tot2 = ;
char a[][]; int getnum(int x, int y)
{
return (x - ) * m + y;
} #define pr pair<int, int>
#define mp make_pair
vector<pr> E[max_map];
struct Node
{
int x, y, dis;
};
const int dx[] = {-, , , }, dy[] = {, , , -};
bool vis[][];
void bfs1(int x, int y)
{
Mem(vis, );
int u = getnum(x, y);
queue<Node> q; q.push((Node){x, y, });
vis[x][y] = ;
while(!q.empty())
{
int x = q.front().x, y = q.front().y, Dis = q.front().dis;
q.pop();
for(int i = ; i < ; ++i)
{
int newx = x + dx[i], newy = y + dy[i];
if(newx > && newx <= n && newy > && newy <= m && a[newx][newy] == '.' && !vis[newx][newy])
{
E[u].push_back(mp(getnum(newx, newy), Dis + ));
vis[newx][newy] = ;
q.push((Node){newx, newy, Dis + });
}
}
} } void init()
{
for(int i = ; i <= n; ++i)
for(int j = ; j <= m; ++j)
{
if(a[i][j] == '.') tot1++;
if(a[i][j] == 'D') tot2++, bfs1(i, j);
}
} struct Edge
{
int from, to, cap, flow;
};
vector<Edge> edges;
vector<int> G[maxn];
void addEdge(int from, int to, int w)
{
edges.push_back((Edge){from, to, w, });
edges.push_back((Edge){to, from, , });
int sz = edges.size();
G[from].push_back(sz - );
G[to].push_back(sz - );
} void build_Gra(int x)
{
edges.clear();
for(int i = ; i <= t; ++i) G[i].clear();
int cnt = ;
for(int i = ; i <= n; ++i)
for(int j = ; j <= m; ++j)
{
if(a[i][j] == '.') addEdge(, getnum(i, j), );
if(a[i][j] == 'D')
{
int u = getnum(i, j);
int tp = n * m + cnt * x;
for(int k = ; k <= x; ++k) addEdge(tp + k, t, );
for(int k = ; k < x; ++k) addEdge(tp + k, tp + k + , INF);
for(int k = ; k < (int)E[u].size(); ++k)
{
int nod = E[u][k].first, d = E[u][k].second;
if(d <= x) addEdge(nod, tp + d, );
}
cnt++;
}
}
} int dis[maxn];
bool bfs()
{
Mem(dis, ); dis[] = ;
queue<int> q; q.push();
while(!q.empty())
{
int now = q.front(); q.pop();
for(int i = ; i < (int)G[now].size(); ++i)
{
Edge& e = edges[G[now][i]];
if(!dis[e.to] && e.cap > e.flow)
{
dis[e.to] = dis[now] + ;
q.push(e.to);
}
}
}
return dis[t];
}
int cur[maxn];
int dfs(int now, int res)
{
if(now == t || res == ) return res;
int flow = , f;
for(int& i = cur[now]; i < (int)G[now].size(); ++i)
{
Edge& e = edges[G[now][i]];
if(dis[e.to] == dis[now] + && (f = dfs(e.to, min(res, e.cap - e.flow))) > )
{
e.flow += f;
edges[G[now][i] ^ ].flow -= f;
flow += f; res -= f;
if(res == ) break;
}
}
return flow;
} int maxflow()
{
int flow = ;
while(bfs())
{
Mem(cur, );
flow += dfs(, INF);
}
return flow;
} int main()
{
n = read(); m = read();
for(int i = ; i <= n; ++i) scanf("%s", a[i] + );
init();
t = n * m * (tot2 + ) + ;
int L = , R = n * m + ;
while(L < R)
{
int mid = (L + R) >> ;
build_Gra(mid);
if(maxflow() >= tot1) R = mid;
else L = mid + ;
}
if(L > n * m) printf("impossible\n");
else write(L), enter;
return ;
}

[HNOI2007]紧急疏散EVACUATE的更多相关文章

  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. [HNOI2007]紧急疏散EVACUATE (湖南2007年省选)

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

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

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

  6. bzoj 1189 [HNOI2007]紧急疏散evacuate 二分+网络流

    [HNOI2007]紧急疏散evacuate Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 3626  Solved: 1059[Submit][St ...

  7. 【二分答案】【最大流】[HNOI2007]紧急疏散EVACUATE

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

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

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

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

    [HNOI2007]紧急疏散evacuate 思路: 处理每个人到门的最短路: 然后二分答案: s向人连边流量1: 人向门拆分后的点连边流量1(拆成400,前一个点连当前点流量INF): 然后门向t连 ...

  10. P3191 [HNOI2007]紧急疏散EVACUATE(费用流)

    P3191 [HNOI2007]紧急疏散EVACUATE 费用流+卡常优化 我们只关心一个人通过门时的时间,在空地的行走时间可以分层维护 于是根据时间分层,到门的时候再计算代价,即代价$=$层数 每经 ...

随机推荐

  1. (微信小程序)二 : 创建一个页面

    首先先看一下pages的目录结构吧. 我创建了一个topics页面.3个文件全创建好了之后 我往topics.js添加数据 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ...

  2. Expression Blend实例中文教程(13) - 控件模板快速入门ControlTemplates

    上篇,介绍了控件样式(Style)和模板(Template)的基础概念,并且演示了使用Blend设计控件样式.本篇将继续介绍使用Blend设计自定义控件模板 - ControlTemplate.Con ...

  3. java泛型使用

    泛型的解释 现在感觉泛型是一个值得学习的地方,就抽出时间来学习和总结一下泛型的使用. Java 泛型(generics)是 JDK 5 中引入的一个新特性, 泛型提供了编译时类型安全检测机制,该机制允 ...

  4. spring的事务管理配置

    spring有两种事务配置器,可以使用spring的jdbc事务管理器,也可以使用对hibernate的事务管理器 第一种 使用Spring JDBC或IBatis进行事务配置(配置文件方式): &l ...

  5. java读取txt文件,对字符串进行操作后导出txt文件

    嘿嘿,代码略为简单,不再多做解释,直接上码! package org.lq.com.util; import java.io.File; import java.io.InputStreamReade ...

  6. Linux_vim文本编辑器指令整理

    一般指令模式 : 可以移动光标,可以删除字符和删除整列,可以复制粘贴 编辑模式 : 按下"i, I, o, O, a, A, r, R"任意一个字母时进入;按下ESC退出编辑模式 ...

  7. Sqoop迁移Hadoop与RDBMS间的数据

    Sqoop是用来实现结构型数据(如:关系型数据库RDBMS)和Hadoop之间进行数据迁移的工具.它充分利用了MapReduce的并行特点以批处理的方式加快数据的传输,同时也借助MapReduce实现 ...

  8. hdu 3535 (最少1,最多1,任意)(背包混合)(好题)

    http://blog.csdn.net/yan_____/article/details/8530833 这个问题一开始我用滚动,没有做出来,可能要需要先预处理排序才行,后来看了别人的方法,开始用二 ...

  9. Docker简单说明

    前段时间工作需要,简单的研究了下docker.侧重点放在docker的镜像定制方面,后续会研究下k8s的使用. Docker是一个开源的引擎,可以轻松的为任何应用创建一个轻量级的.可移植的.自给自足的 ...

  10. Python基础-接口与归一化设计、抽象类、继承顺序、子类调用父类,多态与多态性

    一.接口与归一化设计 Java接口是一系列方法的声明,是一些方法特征的集合,一个接口只有方法的特征没有方法的实现,因此这些方法可以在不同的地方被不同的类实现,而这些实现可以具有不同的行为(功能). 由 ...