Skip to content
Snippets Groups Projects
Commit d2d0d507 authored by Lukas Garbas's avatar Lukas Garbas
Browse files

Edmonds-Karp Max Flow

parent 1c83ac04
No related merge requests found
#include <limits>
#include <queue>
#include <cassert>
#include <gp-bnb/edmonds_karp.hpp>
edmonds_karp::edmonds_karp(const graph &g, node_id source, node_id sink)
: g(g), source(source), sink(sink) {
assert(source > 0); // Nodes have ids: 1, .., n
assert(source < g.num_nodes());
};
/* Indexes edges of the graph
Every edge in the graph is mapped to its unique id
indexed_edges std::map consists of key: pair<node_id, node_id> value: edge_id */
void edmonds_karp::index_edges() {
unsigned int num_nodes = g.num_nodes();
node_id u = 1;
unsigned int eid = 0;
for (unsigned int i = 0; i < num_nodes; i++) {
std::vector<node_id> neighbors = g.get_adjacency(u);
for (node_id v : neighbors) {
auto node_pair = std::make_pair(u, v);
// edge was already listed
if (indexed_edges.count(std::make_pair(v, u)) == 1) {
indexed_edges[node_pair] = indexed_edges.at(std::make_pair(v, u));
} else {
indexed_edges[node_pair] = eid;
eid++;
}
}
u++;
}
}
/* Breadth-first search in the graph from source to sink
When the sink is reached gain is added to gain[sink] */
int edmonds_karp::bfs(std::vector<int> &resid_flow, std::vector<unsigned int> &pred) const {
pred.clear();
pred.resize(g.num_nodes() + 1, -1 ); // undiscovered nodes are marked with -1
std::vector<int> gain(g.num_nodes(), 0.0);
std::queue<node_id> q;
q.push(source);
pred[source] = source;
gain[source] = std::numeric_limits<int>::max();
while (!q.empty()) {
node_id u = q.front();
q.pop();
bool sink_reached = false;
std::vector<node_id> neighbors = g.get_adjacency(u);
// iterate through neighbors of u
for (node_id v : neighbors) {
unsigned int edge_id = indexed_edges.at(std::make_pair(u, v));
int edge_weight = 1; // unweighted graph
if (((u >= v && flow[edge_id] < edge_weight)
|| ( u < v && resid_flow[edge_id] < edge_weight))
&& pred[v] == (unsigned int) -1) { // only add those neighbors with rest capacity and which were not discovered yet
pred[v] = u;
gain[v] = std::min(gain[u], edge_weight - (u >= v ? flow[edge_id] : resid_flow[edge_id]));
if (v != sink && !sink_reached) {
q.push(v);
} else {
sink_reached = true;
}
}
}
if (sink_reached) {
return gain[sink];
}
}
return 0.0;
};
/* Edmonds-Karp Algorithm for unweighted, undirected graphs
Step 0: Index graph edges
Step 1: Initialize flow and residual flow vectors with length |E|
--Loop:
Step 2: Perform BFS that returns max gain from source to sink in one path
Step 3: Add gain that was calculated during BFS to the flow value. Break from the loop if gain was 0
Step 4: Update flow and residual flow values for each node */
void edmonds_karp::run() {
index_edges();
int num_edges = indexed_edges.size() / 2;
flow.clear();
flow.resize(num_edges, 0.0);
std::vector<int> resid_flow(num_edges, 0.0);
flow_value = 0;
while (true) {
std::vector<node_id> pred;
// Perform BFS that returns max gain from source to sink in one path
int gain = bfs(resid_flow, pred);
// If gain == 0.0 that means there exist no more paths from source to sink
if (gain == 0) break;
// Add gain that was calculated during BFS to the flow value
flow_value += gain;
node_id v = sink;
// Update flow and residual flow values for each edge
while (v != source) {
node_id u = pred[v];
int edge_id = indexed_edges[std::make_pair(u, v)];
if (u >= v) {
flow[edge_id] += gain;
resid_flow[edge_id] -= gain;
} else {
flow[edge_id] -= gain;
resid_flow[edge_id] += gain;
}
v = u;
}
}
};
int edmonds_karp::get_max_flow() const {
return flow_value;
};
\ No newline at end of file
#ifndef EDMONDSKARP_H_
#define EDMONDSKARP_H_
#include "graph.hpp"
#include <vector>
#include <map>
class edmonds_karp {
private:
const graph &g;
std::map<std::pair<node_id, node_id>, int> indexed_edges;
node_id source;
node_id sink;
int flow_value;
std::vector<int> flow;
/**
* Indexes edges of the graph
* Every edge in the graph is mapped to its unique id
*/
void index_edges();
/**
* Performs a breadth-first search on the graph from the source node to find an augmenting path to the sink node respecting the flow values
* @param residFlow The residual flow in the network.
* @param pred Used to store the path from the source to the sink.
* @return The gain in terms of flow.
*/
int bfs(std::vector<int> &resid_flow, std::vector<unsigned int> &pred) const;
public:
/**
* Constructs an instance of the EdmondsKarp algorithm for the given graph, source and sink
* @param graph The graph.
* @param source The source node.
* @param sink The sink node.
*/
edmonds_karp(const graph &g, node_id source, node_id sink);
/**
* Computes the maximum flow, executes the EdmondsKarp algorithm.
* For unweighted, undirected Graphs.
*/
void run();
/**
* Returns the value of the maximum flow from source to sink.
*
* @return The maximum flow value
*/
int get_max_flow() const;
};
#endif /* EDMONDSKARP_H_ */
\ No newline at end of file
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment