最大流 Dinic算法

时间:2021-10-20 21:31:36

Ford-Fulkerson算法是通过深度优先搜索寻找增广路,并沿着它增广。

与之相对,Dinic算法总是寻找最短的增广路,并沿着它增广。因为最短增广路的长度在增广过程中始终不会变短,所以无需每次都通过宽度预先搜索来寻找最短增广路。

我们可以先进行一次宽度优先搜索,然后考虑由进距离顶点指向远距离顶点的边所组成的分层图,在上面进行深度优先搜索寻找最短增广路。

如果在分层图上找不到新的增广路,则说明最短增长路的长度确实边长了,或不存在增广路,于是重新通过宽度优先搜索构造新的分层图。每一步构造分层图的复杂度为O(|E|),而每一步完成之后最短增广路的长度都会至少增加1,由于增广路的长度不会超过|V|-1,因此最多重复O(|V|)步就可以了。

另外,在每次对分层图进行宽度优先搜索寻找增广路时,如果避免对一条没有用的边进行多次查找,就可以保证复杂度为O(|E||V|),这样总的复杂度就是O(|E||V|^2)。

 

HDU1532为例,这题用Ford-Fulkerson算法会超时,而用Dinic算法就不会。

 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <string.h>
 4 #include <vector>
 5 #include <queue>
 6 #define INF 0x3f3f3f3f
 7 using namespace std;
 8 const int MAX = 220;
 9 int n, m;
10 struct Nod {
11     int to, cap, rev;
12 };
13 vector<Nod> G[MAX];
14 int level[MAX], iter[MAX];
15 void add_edge(int from, int to, int cap) {
16     G[from].push_back((Nod){to,cap,(int)G[to].size()});
17     G[to].push_back((Nod){from,0,(int)G[from].size()-1});
18 }
19 void bfs(int s) {
20     memset(level, -1, sizeof(level));
21     queue<int> que;
22     level[s] = 0;
23     que.push(s);
24     while(!que.empty()) {
25         int v = que.front(); que.pop();
26         for(int i = 0; i < G[v].size(); i ++) {
27             Nod &e = G[v][i];
28             if(e.cap > 0 && level[e.to] < 0){
29                 level[e.to] = level[v] + 1;
30                 que.push(e.to);
31             }
32         }
33     }
34 }
35 int dfs(int v, int t, int f) {
36     if(v == t) return f;
37     for(int &i = iter[v]; i < G[v].size(); i ++) {
38         Nod &e = G[v][i];
39         if(e.cap > 0 && level[v] < level[e.to]) {
40             int d = dfs(e.to, t, min(f,e.cap));
41             if(d > 0) {
42                 e.cap -= d;
43                 G[e.to][e.rev].cap += d;
44                 return d;
45             }
46         }
47     }
48     return 0;
49 }
50 int max_flow(int s, int t) {
51     int flow = 0;
52     while(1) {
53         bfs(s);
54         if(level[t] < 0) return flow;
55         memset(iter,0,sizeof(iter));
56         int f;
57         while((f = dfs(s, t, INF)) > 0) flow += f;
58     }
59 }
60 int main() {
61     while(scanf("%d %d",&n, &m) != EOF) {
62         for(int i = 0; i < n; i ++) {
63             int u, v, w;
64             scanf("%d %d %d",&u, &v, &w);
65             add_edge(u, v, w);
66         }
67         printf("%d\n",max_flow(1,m));
68         for(int i = 0; i <= m; i ++) G[i].clear();
69     }
70     return 0;
71 }