-
Notifications
You must be signed in to change notification settings - Fork 1.5k
/
edmonds_karp.h
156 lines (131 loc) · 4.15 KB
/
edmonds_karp.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
/*******************************************************************************
* DANIEL'S ALGORITHM IMPLEMENTAIONS
*
* /\ | _ _ ._ o _|_ |_ ._ _ _
* /--\ | (_| (_) | | |_ | | | | | _>
* _|
*
* EDMONS-KARP ALGORITM
*
* Features:
* In computer science and graph theory, the Edmonds–Karp algorithm is an
* implementation of the Ford–Fulkerson method for computing the maximum flow in
* a flow network in O(V E2) time. It is asymptotically slower than the
* relabel-to-front algorithm, which runs in O(V3) time, but it is often faster
* in practice for sparse graphs. The algorithm was first published by Yefim
* (Chaim) Dinic in 1970[1] and independently published by Jack Edmonds and
* Richard Karp in 1972.[2] Dinic's algorithm includes additional techniques
* that reduce the running time to O(V2E).
*
* http://en.wikipedia.org/wiki/Edmonds–Karp_algorithm
*
******************************************************************************/
#ifndef ALGO_EDMONDS_KARP_H__
#define ALGO_EDMONDS_KARP_H__
#include <stdlib.h>
#include <stdint.h>
#include <limits.h>
#include "directed_graph.h"
#include "hash_table.h"
#include "queue.h"
#include "2darray.h"
namespace alg {
/**
* Edmonds Karp maximal flow class
*/
class EdmondsKarp {
private:
const Graph & g;
Array2D<int32_t> m_residual; // residual network , 2d array
HashTable<int32_t, int32_t> m_pre; // pre node of current node
bool * m_visits; // mark whether current node is visited
HashTable<int32_t, int32_t> m_map; // vertex id to ordinary row/col number mapping
HashTable<int32_t, int32_t> m_rmap; // reverse mapping of map.
public:
EdmondsKarp(const Graph & graph): g(graph),
m_residual(g.vertex_count(), g.vertex_count()),
m_pre(g.vertex_count()),
m_map(g.vertex_count()), m_rmap(g.vertex_count()) {
m_visits = new bool[g.vertex_count()];
// map vertex ids to ordinal row/col number, and reverse mapping.
// for residual network, using sequential order
Graph::Adjacent * a;
int id=0;
list_for_each_entry(a, &g.list(), a_node){
m_map[a->v.id] = id;
m_rmap[id] = a->v.id;
id++;
}
// init residual network
m_residual.clear(0);
list_for_each_entry(a, &g.list(), a_node){
Graph::Vertex * v;
list_for_each_entry(v, &a->v_head, v_node){
int from = m_map[a->v.id];
int to = m_map[v->id];
m_residual(from, to) = v->weight;
}
}
}
~EdmondsKarp() {
delete [] m_visits;
}
/**
* edmonds karp algorithm for maximal flow
* returns the maxflow from src to sink
*/
uint32_t run(int32_t src, int32_t sink) {
// find augument path repeatedly.
int32_t _src = m_map[src];
int32_t _sink = m_map[sink];
uint32_t maxflow = 0;
while(find_path(_src, _sink)) {
int delta = INT_MAX;
// find minimal delta
int i;
for (i=_sink;i!=_src;i= m_pre[i]) {
delta = Min(delta, m_residual(m_pre[i],i));
}
// for each edge, change residual network
for (i=_sink; i!=_src;i= m_pre[i]) {
m_residual(m_pre[i],i) -= delta;
m_residual(i,m_pre[i]) += delta;
}
maxflow += delta;
}
return maxflow;
}
inline const Array2D<int> & residual() const { return m_residual;}
inline const HashTable<int32_t, int32_t> & map() const { return m_map;}
inline const HashTable<int32_t, int32_t> & rmap() const { return m_rmap;}
private:
/**
* find a augument path. using breadth first search
*/
bool find_path(int32_t _src, int32_t _sink) {
Queue<int32_t> Q(g.vertex_count());
// clear visit flag & path
memset(m_visits, false, sizeof(bool) * g.vertex_count());
// src setting
m_pre[_src] = _src;
m_visits[_src] = true;
Q.enqueue(_src);
while(!Q.is_empty()) {
int p = Q.front();
Q.dequeue();
for (uint32_t i=0;i< g.vertex_count();i++) {
if (m_residual(p,i) >0 && !m_visits[i]) {
m_pre[i] = p;
m_visits[i] = true;
if (i==uint32_t(_sink)) { // nice, we've got to sink point.
return true;
}
Q.enqueue(i);
}
}
}
return false;
}
};
}
#endif //