题目链接

给一个n*m的图, 里面有一些点, '.'代表空地, '#'代表墙, 不可以走, '@'代表大门, 可以有多个, 'X'代表人, 问所有人都走出大门需要的最短时间, 每一时刻一个格子只能有一个人, 每个时刻只能有一个人从大门走出, 如果不能走出, 输出-1。

先dfs判断是否每个人都能走出, 如果有人不能, 直接输出-1。

从小到大枚举时间, 对于枚举的时间t, 每个格子i, j向它四周以及他本身建边, ( i*m+j+(t-1)*nm, x*m+y+t*nm, 1), 这样就相当于t-1时刻的点向t时刻的点连了一条边。 然后每个出口向汇点连边, (x*m+y+t*nm, 汇点, 1)。 源点向0时刻的每个人连边, 只连一次。

这样每次都跑一遍网络流, 如果结果ans等于人数sum, 那么说明这个时刻是最小时刻, 需要注意的是, 如果结果不等于人数, 那么sum -= ans。

具体看代码。

 #include<bits/stdc++.h>
using namespace std;
#define mem(a) memset(a, 0, sizeof(a))
#define mem1(a) memset(a, -1, sizeof(a))
#define mem2(a) memset(a, 0x3f, sizeof(a))
const int inf = ;
const int dir[][] = { {-, }, {, }, {, -}, {, },{, } };
const int maxn = 2e6+;
int q[maxn*], head[maxn*], dis[maxn/], s, t, m, n, vis[][], num, flag, sum;
char c[][];
struct node
{
int to, nextt, c;
node(){}
node(int to, int nextt, int c):to(to), nextt(nextt), c(c){}
}e[maxn*];
void init() {
num = flag = sum = ;
mem1(head);
}
void add(int u, int v, int c) {
e[num] = node(v, head[u], c); head[u] = num++;
e[num] = node(u, head[v], ); head[v] = num++;
}
int bfs() {
mem(dis);
dis[s] = ;
int st = , ed = ;
q[ed++] = s;
while(st<ed) {
int u = q[st++];
for(int i = head[u]; ~i; i = e[i].nextt) {
int v = e[i].to;
if(!dis[v]&&e[i].c) {
dis[v] = dis[u]+;
if(v == t)
return ;
q[ed++] = v;
}
}
}
return ;
}
int dfs(int u, int limit) {
if(u == t) {
return limit;
}
int cost = ;
for(int i = head[u]; ~i; i = e[i].nextt) {
int v = e[i].to;
if(e[i].c&&dis[v] == dis[u]+) {
int tmp = dfs(v, min(limit-cost, e[i].c));
if(tmp>) {
e[i].c -= tmp;
e[i^].c += tmp;
cost += tmp;
if(cost == limit)
break;
} else {
dis[v] = -;
}
}
}
return cost;
}
int dinic() {
int ans = ;
while(bfs()) {
ans += dfs(s, inf);
}
return ans;
}
// 上面是模板
int judge(int x, int y) {
if(x>=&&x<n&&y>=&&y<m&&c[x][y]!='#'&&!vis[x][y])
return ;
return ;
} int dfs1(int x, int y) {
for(int i = ; i<; i++) {
int tmpx = x+dir[i][];
int tmpy = y+dir[i][]; //判断能否走出
if(judge(tmpx, tmpy)) {
if(c[tmpx][tmpy]=='@')
return ;
vis[tmpx][tmpy] = ;
if(dfs1(tmpx, tmpy))
return ;
}
}
return ;
} int ok(int deep) { //枚举时间, 每一次枚举, 都在原有的图的基础上继续建边,因为原图已经跑过一遍最大流, 所以每次结束后
int nm = n*m; //总人数都应该减去每一次的结果, 意思是已经有那么多的人跑了出去。
for(int i = ; i<n; i++) {
for(int j = ; j<m; j++) {
if(c[i][j] == '@') {
add(i*m+j+nm*deep+, t, ); //对于每一时刻, 出口都要向汇点建边。
continue;
}
if(c[i][j]=='#')
continue;
for(int k = ; k<; k++) {
int x = i+dir[k][];
int y = j+dir[k][];
if(judge(x, y)) {
add(i*m+j+(deep-)*nm+, x*m+y+deep*nm+, ); //前一时刻的点向这一时刻建边。
}
}
}
}
int ans = dinic();
if(ans == sum)
return ;
sum -= ans; //这里十分重要啊....
return ;
} int main()
{
while(~scanf("%d%d", &n, &m)) {
init();
for(int i = ; i<n; i++)
scanf("%s", c[i]);
s = , t = ;
for(int i = ; i<n; i++) {
for(int j = ; j<m; j++) {
if(c[i][j] == 'X') {
add(s, i*m+j+, ); //源点向0时刻的每一个人连边
mem(vis);
sum++;
if(!dfs1(i, j)) {
flag = ;
}
}
}
}
if(flag) {
puts("-1");
continue;
}
mem(vis);
int ans;
for(ans = ; ; ans++) {
if(ok(ans)) //枚举时间
break;
}
cout<<ans<<endl;
}
}

hdu 3572 Escape 网络流的更多相关文章

  1. HDU 3605 Escape (网络流,最大流,位运算压缩)

    HDU 3605 Escape (网络流,最大流,位运算压缩) Description 2012 If this is the end of the world how to do? I do not ...

  2. Hdu 3605 Escape (最大流 + 缩点)

    题目链接: Hdu 3605  Escape 题目描述: 有n个人要迁移到m个星球,每个星球有最大容量,每个人有喜欢的星球,问是否所有的人都能迁移成功? 解题思路: 正常情况下建图,不会爆内存,但是T ...

  3. HDU 3572 Task Schedule(拆点+最大流dinic)

    Task Schedule Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) To ...

  4. HDU 3533 Escape(大逃亡)

    HDU 3533 Escape(大逃亡) /K (Java/Others)   Problem Description - 题目描述 The students of the HEU are maneu ...

  5. HDU 3572 Task Schedule (最大流)

    C - Task Schedule Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u S ...

  6. hdu 3572 Task Schedule 网络流

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3572 Our geometry princess XMM has stoped her study i ...

  7. HDU 3036 Escape 网格图多人逃生 网络流||二分匹配 建图技巧

    题意: 每一个' . '有一个姑娘, E是出口,'.'是空地 , 'X' 是墙. 每秒钟每一个姑娘能够走一步(上下左右) 每秒钟每一个出口仅仅能出去一个人 给定n*m的地图, 时限T 问全部姑娘是否能 ...

  8. hdu 3572 : Task Schedule (网络流)

    题目链接 题意: 有M个机器,N个任务 对第i个任务,需要在[Si,Ei]这段时间内恰有Pi天被process 每天最多有M个机器同时工作 每一天,一个任务若被process,那么它恰占用一个机器. ...

  9. 图论--网络流--最大流 HDU 3572 Task Schedule(限流建图,超级源汇)

    Problem Description Our geometry princess XMM has stoped her study in computational geometry to conc ...

随机推荐

  1. javascript高级知识分析——上下文

    如果函数是一个对象的属性,那么它可以? var katana = { isSharp: true, use: function(){ this.isSharp = !this.isSharp; } } ...

  2. 如果不知道MySQL当前使用配置文件(my.cnf)的路径的解决方法

    如果不知道当前使用的配置文件的路径,可以尝试下面的操作: # which mysqld /usr/local/mysql/bin/mysqld # /usr/local/mysql/bin/mysql ...

  3. HTTP填坑

    HTTP知识填坑 .note-content {font-family: "Helvetica Neue",Arial,"Hiragino Sans GB",& ...

  4. 《javascript dom编程艺术》笔记(一)——优雅降级、向后兼容、多个函数绑定onload函数

    刚刚开始自学前端,如果不对请指正:欢迎各位技术大牛指点. 开始学习<javascript dom编程艺术>,整理一下学习到的知识.今天刚刚看到第六章,记下get到的几个知识点. 优雅降级 ...

  5. struts2笔记03-ActionContext

    1.概念 ActionContext是action的上下文,它包括action执行所需要的对象.struts2对每一个action都会创建一个新的ActionContext实例,同Action一样,是 ...

  6. codeforces 665D Simple Subset

    题目链接 给一个数列, 让你选出其中的m个数, 使得选出的数中任意两个数之和都为质数, m尽可能的大. 首先, 除了1以外的任意两个相同的数相加结果都不是质数. 然后, 不考虑1的话, 选出的数的个数 ...

  7. 【Chromium中文文档】Chromium如何展示网页

    Chromium如何展示网页 转载请注明出处:https://ahangchen.gitbooks.io/chromium_doc_zh/content/zh//Start_Here_Backgrou ...

  8. 发送邮件java实现

    下面代码可以实现普通qq邮箱发送邮件的功能,可以传附件,但是是固定的附件: 需要两个jar包:mail.jar,activation.jar mail.jar 下载地址: http://java.su ...

  9. android在桌面弹出一个窗口

    android在桌面弹出一个窗口 遇到了这种需求,要和iPhone一样的效果. 下面是简单实现功能,优化和美化部分,有时间慢慢搞. 方法应该有不少吧,我用的是弹出一个activity,将这个activ ...

  10. NOI2013 Day1

    NOI2013 Day1 向量内积 题目描述:两个\(d\)维向量\(A\)与\(B\)的内积为其相对应维度的权值的乘积和,现有\(n\)个\(d\)维向量 ,求是否存在两个向量的内积为\(k\)(\ ...