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

multiple sources and sinks

parent 38ef3f65
No related merge requests found
#include <limits> #include <limits>
#include <queue> #include <queue>
#include <cassert> #include <cassert>
#include <algorithm>
#include <gp-bnb/edmonds_karp.hpp> #include <gp-bnb/edmonds_karp.hpp>
edmonds_karp::edmonds_karp(const graph &g, node_id source, node_id sink) edmonds_karp::edmonds_karp(const graph &g, std::vector<node_id> sources, std::vector<node_id> sinks)
: g_(g), source_(source), sink_(sink) { : g_(g), sources_(sources), sinks_(sinks) {
assert(source_ > 0); // Nodes have ids: 1, .., n
assert(source_ <= g.num_nodes());
}; };
/* Indexes edges of the graph /* Indexes edges of the graph
...@@ -37,24 +36,29 @@ void edmonds_karp::index_edges() { ...@@ -37,24 +36,29 @@ void edmonds_karp::index_edges() {
} }
} }
/* Breadth-first search in the graph from source to sink /* Breadth-first search in the graph from source nodes to sink nodes */
When the sink is reached gain is added to gain[sink] */ std::pair<int, node_id> edmonds_karp::bfs(std::vector<int> &resid_flow, std::vector<unsigned int> &pred) const {
int edmonds_karp::bfs(std::vector<int> &resid_flow, std::vector<unsigned int> &pred) const {
pred.clear(); pred.clear();
pred.resize(g_.num_nodes() + 1, -1 ); // undiscovered nodes are marked with -1 pred.resize(g_.num_nodes() + 1, -1); // undiscovered nodes are marked with -1
std::vector<int> gain(g_.num_nodes(), 0.0); std::vector<int> gain(g_.num_nodes(), 0);
bool sink_reached = false;
node_id sink;
// Push all source nodes to the queue
std::queue<node_id> q; std::queue<node_id> q;
q.push(source_); for (node_id s : sources_) {
pred[source_] = source_; q.push(s);
gain[source_] = std::numeric_limits<int>::max(); pred[s] = s;
while (!q.empty()) { gain[s] = std::numeric_limits<int>::max();
}
// Perform BFS from each source node and stop when the sink was reached
// or there was no path found from the source to the sink
while (!q.empty() && !sink_reached) {
node_id u = q.front(); node_id u = q.front();
q.pop(); q.pop();
bool sink_reached = false;
std::vector<node_id> neighbors = g_.get_adjacency(u); std::vector<node_id> neighbors = g_.get_adjacency(u);
// iterate through neighbors of u // iterate through neighbors of u
...@@ -67,19 +71,23 @@ int edmonds_karp::bfs(std::vector<int> &resid_flow, std::vector<unsigned int> &p ...@@ -67,19 +71,23 @@ int edmonds_karp::bfs(std::vector<int> &resid_flow, std::vector<unsigned int> &p
&& pred[v] == (unsigned int) -1) { // only add those neighbors with rest capacity and which were not discovered yet && pred[v] == (unsigned int) -1) { // only add those neighbors with rest capacity and which were not discovered yet
pred[v] = u; pred[v] = u;
gain[v] = std::min(gain[u], edge_weight - (u >= v ? flow_[edge_id] : resid_flow[edge_id])); gain[v] = std::min(gain[u], edge_weight - (u >= v ? flow_[edge_id] : resid_flow[edge_id]));
if (v != sink_ && !sink_reached) {
if (!sink_reached) {
q.push(v); q.push(v);
} else { sink = v;
sink_reached = true;
} }
// Check if any of the sink nodes are reached
for (node_id t : sinks_)
if (v == t) sink_reached = true;
} }
} }
if (sink_reached) { if (sink_reached)
return gain[sink_]; return std::make_pair(gain[sink], sink);
}
} }
return 0.0;
return std::make_pair(0.0, sink);
}; };
...@@ -91,31 +99,36 @@ Step 2: Perform BFS that returns max gain from source to sink in one path ...@@ -91,31 +99,36 @@ 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 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 */ Step 4: Update flow and residual flow values for each node */
void edmonds_karp::run() { void edmonds_karp::run() {
index_edges(); index_edges();
int num_edges = indexed_edges_.size() / 2; int num_edges = indexed_edges_.size() / 2;
flow_.clear(); flow_.clear();
flow_.resize(num_edges, 0.0); flow_.resize(num_edges, 0);
std::vector<int> resid_flow(num_edges, 0.0); std::vector<int> resid_flow(num_edges, 0);
flow_value_ = 0; flow_value_ = 0;
while (true) { while (true) {
std::vector<node_id> pred; 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 // BFS from source nodes to sink nodes
auto bfs_result = bfs(resid_flow, pred);
int gain = bfs_result.first;
node_id v = bfs_result.second;
if (gain == 0) break; if (gain == 0) break;
// Add gain that was calculated during BFS to the flow value // Add gain that was calculated during BFS to the flow value
flow_value_ += gain; flow_value_ += gain;
node_id v = sink_;
// Update flow and residual flow values for each edge // Update flow and residual flow values for each edge
while (v != source_) { // in the path from the sink node to the source node
bool source_reached = false;
while (!source_reached) {
node_id u = pred[v]; node_id u = pred[v];
int edge_id = indexed_edges_[std::make_pair(u, v)]; int edge_id = indexed_edges_[std::make_pair(u, v)];
if (u >= v) { if (u >= v) {
flow_[edge_id] += gain; flow_[edge_id] += gain;
resid_flow[edge_id] -= gain; resid_flow[edge_id] -= gain;
...@@ -123,9 +136,12 @@ void edmonds_karp::run() { ...@@ -123,9 +136,12 @@ void edmonds_karp::run() {
flow_[edge_id] -= gain; flow_[edge_id] -= gain;
resid_flow[edge_id] += gain; resid_flow[edge_id] += gain;
} }
v = u; v = u;
source_reached = std::find(sources_.begin(), sources_.end(), v) != sources_.end();
} }
} }
}; };
int edmonds_karp::get_max_flow() const { int edmonds_karp::get_max_flow() const {
......
#ifndef EDMONDSKARP_H_ #ifndef EDMONDSKARP_H_
#define EDMONDSKARP_H_ #define EDMONDSKARP_H_
#include "graph.hpp"
#include <vector> #include <vector>
#include <map> #include <map>
#include <gp-bnb/graph.hpp>
class edmonds_karp { class edmonds_karp {
private: private:
...@@ -11,8 +11,8 @@ private: ...@@ -11,8 +11,8 @@ private:
std::map<std::pair<node_id, node_id>, unsigned int> indexed_edges_; std::map<std::pair<node_id, node_id>, unsigned int> indexed_edges_;
node_id source_; std::vector<node_id> sources_;
node_id sink_; std::vector<node_id> sinks_;
int flow_value_; int flow_value_;
std::vector<int> flow_; std::vector<int> flow_;
...@@ -26,9 +26,9 @@ private: ...@@ -26,9 +26,9 @@ private:
* 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 * 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 residFlow The residual flow in the network.
* @param pred Used to store the path from the source to the sink. * @param pred Used to store the path from the source to the sink.
* @return The gain in terms of flow. * @return The gain in terms of flow and id of the sink node.
*/ */
int bfs(std::vector<int> &resid_flow, std::vector<unsigned int> &pred) const; std::pair<int, node_id> bfs(std::vector<int> &resid_flow, std::vector<unsigned int> &pred) const;
public: public:
/** /**
...@@ -37,7 +37,7 @@ public: ...@@ -37,7 +37,7 @@ public:
* @param source The source node. * @param source The source node.
* @param sink The sink node. * @param sink The sink node.
*/ */
edmonds_karp(const graph &g, node_id source, node_id sink); edmonds_karp(const graph &g, std::vector<node_id> sources, std::vector<node_id> sinks);
/** /**
* Computes the maximum flow, executes the EdmondsKarp algorithm. * Computes the maximum flow, executes the EdmondsKarp algorithm.
......
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