hdu 3572 Escape 网络流

题目链接

给一个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。

具体看代码。

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 #define mem(a) memset(a, 0, sizeof(a))
  4 #define mem1(a) memset(a, -1, sizeof(a))
  5 #define mem2(a) memset(a, 0x3f, sizeof(a))
  6 const int inf = 1061109567;
  7 const int dir[][2] = { {-1, 0}, {1, 0}, {0, -1}, {0, 1},{0, 0} };
  8 const int maxn = 2e6+5;
  9 int q[maxn*2], head[maxn*2], dis[maxn/10], s, t, m, n, vis[30][30], num, flag, sum;
 10 char c[30][30];
 11 struct node
 12 {
 13     int to, nextt, c;
 14     node(){}
 15     node(int to, int nextt, int c):to(to), nextt(nextt), c(c){}
 16 }e[maxn*2];
 17 void init() {
 18     num = flag = sum = 0;
 19     mem1(head);
 20 }
 21 void add(int u, int v, int c) {
 22     e[num] = node(v, head[u], c); head[u] = num++;
 23     e[num] = node(u, head[v], 0); head[v] = num++;
 24 }
 25 int bfs() {
 26     mem(dis);
 27     dis[s] = 1;
 28     int st = 0, ed = 0;
 29     q[ed++] = s;
 30     while(st<ed) {
 31         int u = q[st++];
 32         for(int i = head[u]; ~i; i = e[i].nextt) {
 33             int v = e[i].to;
 34             if(!dis[v]&&e[i].c) {
 35                 dis[v] = dis[u]+1;
 36                 if(v == t)
 37                     return 1;
 38                 q[ed++] = v;
 39             }
 40         }
 41     }
 42     return 0;
 43 }
 44 int dfs(int u, int limit) {
 45     if(u == t) {
 46         return limit;
 47     }
 48     int cost = 0;
 49     for(int i = head[u]; ~i; i = e[i].nextt) {
 50         int v = e[i].to;
 51         if(e[i].c&&dis[v] == dis[u]+1) {
 52             int tmp = dfs(v, min(limit-cost, e[i].c));
 53             if(tmp>0) {
 54                 e[i].c -= tmp;
 55                 e[i^1].c += tmp;
 56                 cost += tmp;
 57                 if(cost == limit)
 58                     break;
 59             } else {
 60                 dis[v] = -1;
 61             }
 62         }
 63     }
 64     return cost;
 65 }
 66 int dinic() {
 67     int ans = 0;
 68     while(bfs()) {
 69         ans += dfs(s, inf);
 70     }
 71     return ans;
 72 }
 73 // 上面是模板
 74 int judge(int x, int y) {
 75     if(x>=0&&x<n&&y>=0&&y<m&&c[x][y]!=‘#‘&&!vis[x][y])
 76         return 1;
 77     return 0;
 78 }
 79
 80 int dfs1(int x, int y) {
 81     for(int i = 0; i<4; i++) {
 82         int tmpx = x+dir[i][0];
 83         int tmpy = y+dir[i][1];         //判断能否走出
 84         if(judge(tmpx, tmpy)) {
 85             if(c[tmpx][tmpy]==‘@‘)
 86                 return 1;
 87             vis[tmpx][tmpy] = 1;
 88             if(dfs1(tmpx, tmpy))
 89                 return 1;
 90         }
 91     }
 92     return 0;
 93 }
 94
 95 int ok(int deep) {          //枚举时间, 每一次枚举, 都在原有的图的基础上继续建边,因为原图已经跑过一遍最大流, 所以每次结束后
 96     int nm = n*m;           //总人数都应该减去每一次的结果, 意思是已经有那么多的人跑了出去。
 97     for(int i = 0; i<n; i++) {
 98         for(int j = 0; j<m; j++) {
 99             if(c[i][j] == ‘@‘) {
100                 add(i*m+j+nm*deep+2, t, 1);     //对于每一时刻, 出口都要向汇点建边。
101                 continue;
102             }
103             if(c[i][j]==‘#‘)
104                 continue;
105             for(int k = 0; k<5; k++) {
106                 int x = i+dir[k][0];
107                 int y = j+dir[k][1];
108                 if(judge(x, y)) {
109                     add(i*m+j+(deep-1)*nm+2, x*m+y+deep*nm+2, 1);       //前一时刻的点向这一时刻建边。
110                 }
111             }
112         }
113     }
114     int ans = dinic();
115     if(ans == sum)
116         return 1;
117     sum -= ans;         //这里十分重要啊....
118     return 0;
119 }
120
121 int main()
122 {
123     while(~scanf("%d%d", &n, &m)) {
124         init();
125         for(int i = 0; i<n; i++)
126             scanf("%s", c[i]);
127         s = 0, t = 1;
128         for(int i = 0; i<n; i++) {
129             for(int j = 0; j<m; j++) {
130                 if(c[i][j] == ‘X‘) {
131                     add(s, i*m+j+2, 1);             //源点向0时刻的每一个人连边
132                     mem(vis);
133                     sum++;
134                     if(!dfs1(i, j)) {
135                         flag = 1;
136                     }
137                 }
138             }
139         }
140         if(flag) {
141             puts("-1");
142             continue;
143         }
144         mem(vis);
145         int ans;
146         for(ans = 1; ; ans++) {
147             if(ok(ans))                 //枚举时间
148                 break;
149         }
150         cout<<ans<<endl;
151     }
152 }
时间: 2024-12-14 23:41:46

hdu 3572 Escape 网络流的相关文章

HDU 1733 Escape(分层网络流)

HDU 1733 Escape 题目链接 题意:给定一个图,#是墙,@是出口,.可以行走,X是人,每个时间每个格子只能站一个人,问最少需要多少时间能让人全部撤离(从出口出去) 思路:网络流,把每个结点每秒当成一个结点,这样枚举时间,每多一秒就在原来的网络上直接加一层继续增广即可,注意考虑方向的时候,要考虑上原地不动 代码: #include <cstdio> #include <cstring> #include <queue> #include <algorit

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

前言 在编程过程中总结归纳出来的一种编程经验,从而形成的设计思想称为设计模式. 设计模式有23种.它适用于所有的编程语言. 常用的有创新型的设计模式:简单工厂.抽象工厂和单例模式:行为型的设计模式:模板设计模式.观察者模式和命令模式:结构性的设计模式:适配器设计模式.代理模式(静态和动态两种,典型的有在spring的AOP编程中使用)和装饰器设计模式. 正文 单例模式(singleton) 保证一个类在内存中只能创建一个实例. 1.实现步骤: 1)将构造器私有化,即使用private修饰构造器

hdu 3572 Task Schedule(网络流 dinic算法)

Task Schedule Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 3412    Accepted Submission(s): 1197 Problem Description Our geometry princess XMM has stoped her study in computational geometry t

HDU 3572 Task Schedule(ISAP)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3572 题意:m台机器,需要做n个任务.第i个任务,你需要使用机器Pi天,且这个任务要在[Si  ,  Ei]区间内完成才有效.对于一个任务,只能由一个机器来完成,一个机器同一时间只能做一个任务.当然,一个任务可以分成几段不连续的时间来完成.问,能否做完全部任务. 题意很清晰,也就是判断是否是满流. 对于网络流问题,模板大家都有,关键在于如何建图(详见资料) 思路:今天问了龙哥,对建图有了一定的了解,

Hdu 3605 Escape (最大流 + 缩点)

题目链接: Hdu 3605  Escape 题目描述: 有n个人要迁移到m个星球,每个星球有最大容量,每个人有喜欢的星球,问是否所有的人都能迁移成功? 解题思路: 正常情况下建图,不会爆内存,但是TLE还是稳稳的.以前只遇到过网络流拆点建图,这个正好是缩点建图.吼吼吼~~~,建图的方式还是值得学习的. 因为星球数目最多十个,那么无论有多少个人,其不同选择也就2^10种咯.把不同的选择作为节点,节点就从10^5减少到了2^10,整整缩小了一个数量级呢.建立源点和汇点,源点和选择链接,边权为这种选

HDU 3605 Escape【二分图多重匹配】

题意: 有n个人去m个星球  告诉你每个人想去哪些星球和每个星球最多容纳多少人,问能不能让所有人都满足 分析: 二分图多重匹配 代码: 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <vector> 5 using namespace std; 6 7 const int maxn = 100005; 8 const int maxm = 15; 9 10

HDU 3667 Transportation(网络流之费用流)

题目地址:HDU 3667 这题的建图真是巧妙...为了保证流量正好达到k,需要让每一次增广到的流量都是1,这就需要把每一条边的流量都是1才行.但是每条边的流量并不是1,该怎么办呢.这个时候可以拆边,反正c最多只有5,拆成5条流量为1的边.但是这时候费用怎么办呢,毕竟平方的关系不能简单把每一条边加起来.这时候可以把拆的边的流量设为1,3,5,7,9.如果经过了3个流量,那就肯定会流1,3,5,费用为9,是3的平方,同理,其他的也是如此.然后按照给出的边建图跑一次费用流就可以了. 代码如下: #i

hdu 3572 Task Schedule(最大流)

hdu 3572 Task Schedule Description Our geometry princess XMM has stoped her study in computational geometry to concentrate on her newly opened factory. Her factory has introduced M new machines in order to process the coming N tasks. For the i-th tas

hdu 3605 Escape (二分图多重匹配)

Escape Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 4298    Accepted Submission(s): 1129 Problem Description 2012 If this is the end of the world how to do? I do not know how. But now scient