初涉网络流[EK&dinic]

主要还是板子

Edmonds-Karp

从S开始bfs,直到找到一条到达T的路径后将该路径增广,并重复这一过程。

在处理过程中,为了应对“找到的一条路径把其他路径堵塞”的情况,采用了建反向弧的方式来实现“反悔”过程。

这种“反悔”的想法和技巧值得借鉴。

 1 int maxFlow()
 2 {
 3     int ret = 0;
 4     for (;;)
 5     {
 6         memset(f, 0, sizeof f);
 7         memset(bck, 0, sizeof bck);
 8         std::queue<int> q;
 9         f[S] = INF, q.push(S);
10         for (int tmp; q.size(); )
11         {
12             tmp = q.front(), q.pop();
13             for (int i=head[tmp]; i!=-1; i=nxt[i])
14             {
15                 int v = edges[i].v;
16                 if (!f[v]&&edges[i].f < edges[i].c){
17                     f[v] = std::min(f[tmp], edges[i].c-edges[i].f);
18                     bck[v] = i, q.push(v);
19                 }
20             }
21             if (f[T]) break;
22         }
23         if (!f[T]) break;
24         for (int i=T; i!=S; i=edges[bck[i]].u)
25         {
26             edges[bck[i]].f += f[T];
27             edges[bck[i]^1].f -= f[T];
28         }
29         ret += f[T];
30     }
31     return ret;
32 }

Dinic

EK的效率是$O(nm^2)$的,它把很多时间浪费在了重复的搜索上面。

dinic有如下两个重要的定义:

  • 层次$\text{level(x)}$:表示点$x$在层次图中与源点$S$的距离。
  • 层次图:在原来的残量网络当中,只保留所有可被增广的边以及与之相连的点。

bfs建出来的层次图对于接下去的dfs增广具有一种“指导”作用。使用了反向弧技巧,意味着不管用什么方法,只需要找到一条增广路就行。在这种情况下,我们来考虑dfs增广的优劣之处:一方面它一旦找到一条增广路就能快速退出,比bfs的逐级外扩更高效;另一方面纯粹的dfs受搜索顺序的影响很大,因为(可以像卡SPFA以及某些图论算法一样)挂一些诱导节点附带数量巨大的边,就能置dfs于死地。但是这里dfs依靠建出来的层次图,每次只向距离+1的点搜索。这意味着我们避免了对同一个节点的重复搜索,或是偏离T方向浪费时间。

 1 bool buildLevel()
 2 {
 3     memset(lv, 0, sizeof lv);
 4     std::queue<int> q;
 5     q.push(S), lv[S] = 1;
 6     for (int i=1; i<=T; i++) cur[i] = head[i];   //tip1
 7     for (int tmp; q.size(); )
 8     {
 9         tmp = q.front(), q.pop();
10         for (int i=head[tmp]; i!=-1; i=nxt[i])
11         {
12             int v = edges[i].v;
13             if (!lv[v]&&edges[i].f < edges[i].c){
14                 lv[v] = lv[tmp]+1, q.push(v);
15                 if (v==T) return true;        //tip2
16             }
17         }
18     }
19     return false;
20 }
21 int fndPath(int x, int lim)
22 {
23     if (x==T) return lim;
24     for (int &i=cur[x]; i!=-1; i=nxt[i])       //tip1
25     {
26         int v = edges[i].v, val;
27         if (lv[x]+1==lv[v]&&edges[i].f < edges[i].c){
28             if ((val = fndPath(v, std::min(lim, edges[i].c-edges[i].f)))){
29                 edges[i].f += val, edges[i^1].f -= val;
30                 return val;
31             }else lv[v] = -1;             //tip3  
32         }
33     }
34     cur[x] = head[x];
35     return 0;
36 }
37 int dinic()
38 {
39     int ret = 0, val;
40     while (buildLevel())
41         while ((val = fndPath(S, INF))) ret += val;
42     return ret;
43 }

dinic有三个常见优化:

tip1当前弧优化:这个优化是针对边的,有些网络流的边数巨大。这个优化是为了确保在同一层次图的多次增广当中,可以实现“从上一次成功增广停下的地方再次开始”这一个功能。

tip2层次图优化:每次建层次图只需要达到T即可。

tip3堵塞点优化:姑且这么叫吧……在同一层次图下,一个点若未被增广则再也不会被增广了。

个人觉得tip3的效果最明显。tip1是为了少遍历一些边,但是节省的只不过是遍历(因为并不执行操作)的代价;tip2是看脸的优化;tip3应该算是强剪枝。

原文地址:https://www.cnblogs.com/antiquality/p/10351427.html

时间: 2024-10-15 15:59:44

初涉网络流[EK&dinic]的相关文章

初涉网络流 POJ 1459 Power Network

怒搞一下午网络流,又去我一块心病. 从2F到SAP再到Dinic终于过掉了.可是书上说Dinic的时间复杂度为v*v*e.感觉也应该超时的啊,可是过掉了,好诡异. 后两种算法都是在第一种的基础上进行优化.第一种方法就是不停的寻找增广路,后两种引进了层次网络的概念,第三种又改善了寻找增广路的方法. 现在只能理解到这里了... #include <algorithm> #include <iostream> #include <cstring> #include <c

[知识点]网络流之Dinic算法

// 此博文为迁移而来,写于2014年2月6日,不代表本人现在的观点与看法.原始地址:http://blog.sina.com.cn/s/blog_6022c4720102vrg4.html 今天我们来谈谈网络流之Dinic算法.这种算法相比Edmond-Karp算法,更加快速,更加常用.还记得EK吗?每次为了防止流量堵塞,必须进行多次BFS/DFS,非常费时间.而Dinic大叔非常机智的发明了Dinic算法,让这个问题得以解决. Dinic的核心内容是:反复进行BFS绘制出层次图,和DFS进行

POJ1149_PIGS(网络流/EK)

PIGS Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 15721   Accepted: 7021 Description Mirko works on a pig farm that consists of M locked pig-houses and Mirko can't unlock any pighouse because he doesn't have the keys. Customers come t

POJ 2391 Ombrophobic Bovines (二分,最短路径,网络流sap,dinic,预留推进 )

Ombrophobic Bovines Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 14019   Accepted: 3068 Description FJ's cows really hate getting wet so much that the mere thought of getting caught in the rain makes them shake in their hooves. They h

poj1459 Power Network --- 最大流 EK/dinic

求从电站->调度站->消费者的最大流,给出一些边上的容量,和电站和消费者可以输入和输出的最大量. 添加一个超级源点和汇点,建边跑模板就可以了.两个模板逗可以. #include <iostream> #include <cstring> #include <string> #include <cstdio> #include <cmath> #include <algorithm> #include <vector&

HDU1532_Drainage Ditches(网络流/EK模板)

Drainage Ditches Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 8599    Accepted Submission(s): 4005 Problem Description Every time it rains on Farmer John's fields, a pond forms over Bessie's

网络最大流增广路模板(EK &amp; Dinic)

EK算法: int fir[maxn]; int u[maxm],v[maxm],cap[maxm],flow[maxm],nex[maxm]; int e_max; int p[maxn],q[maxn],d[maxn]; void add_edge(int _u,int _v,int _w) { int e; e=e_max++; u[e]=_u;v[e]=_v;cap[e]=_w; nex[e]=fir[u[e]];fir[u[e]]=e; e=e_max++; u[e]=_v;v[e]=

hiho一下,第115周,FF,EK,DINIC

题目1 : 网络流一·Ford-Fulkerson算法 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 小Hi和小Ho住在P市,P市是一个很大很大的城市,所以也面临着一个大城市都会遇到的问题:交通拥挤. 小Ho:每到周末回家感觉堵车都是一种煎熬啊. 小Hi:平时交通也还好,只是一到上下班的高峰期就会比较拥挤. 小Ho:要是能够限制一下车的数量就好了,不知道有没有办法可以知道交通系统的最大承受车流量,这样就可以限制到一个可以一直很顺畅的数量了. 小Hi:理论上是有算法

POJ - 3436 ACM Computer Factory (ISAP EK Dinic)

题目大意:有N台机器,每台机器能处理相应型态的电脑,处理完后,电脑将变成另一种形态. 每台机器有相应的工作限度,每次至多处理K台 现在问,在一次流水线生产中,最多可以产生多少台完整的电脑(流水线指的是在每一台机器的工作限度下) 解题思路:题目比较难理解,理解题目的话,就比较好做了 首先,将每台机器的点拆成两个点,权值为工作限度 如果机器能处理的电脑的状态全是0的话,就将其和超级源点连接,表示该机器进行第一步加工 如果机器处理完后的形态与另一台机器能处理的最初形态相同,就将其连线,表示下一台机器可