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

multiple sources and sinks

parent 38ef3f65
Branches
No related merge requests found
#include <limits>
#include <queue>
#include <cassert>
#include <algorithm>
#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());
edmonds_karp::edmonds_karp(const graph &g, std::vector<node_id> sources, std::vector<node_id> sinks)
: g_(g), sources_(sources), sinks_(sinks) {
};
/* Indexes edges of the graph
......@@ -37,24 +36,29 @@ void edmonds_karp::index_edges() {
}
}
/* 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 {
/* Breadth-first search in the graph from source nodes to sink nodes */
std::pair<int, node_id> 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);
pred.clear();
pred.resize(g_.num_nodes() + 1, -1); // undiscovered nodes are marked with -1
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;
q.push(source_);
pred[source_] = source_;
gain[source_] = std::numeric_limits<int>::max();
while (!q.empty()) {
for (node_id s : sources_) {
q.push(s);
pred[s] = s;
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();
q.pop();
bool sink_reached = false;
std::vector<node_id> neighbors = g_.get_adjacency(u);
// iterate through neighbors of u
......@@ -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] = u;
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);
} else {
sink_reached = true;
sink = v;
}
// Check if any of the sink nodes are reached
for (node_id t : sinks_)
if (v == t) sink_reached = true;
}
}
if (sink_reached) {
return gain[sink_];
}
if (sink_reached)
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
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_.resize(num_edges, 0);
std::vector<int> resid_flow(num_edges, 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
// 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;
// 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_) {
// Update flow and residual flow values for each edge
// in the path from the sink node to the source node
bool source_reached = false;
while (!source_reached) {
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;
......@@ -123,9 +136,12 @@ void edmonds_karp::run() {
flow_[edge_id] -= gain;
resid_flow[edge_id] += gain;
}
v = u;
source_reached = std::find(sources_.begin(), sources_.end(), v) != sources_.end();
}
}
};
int edmonds_karp::get_max_flow() const {
......
#ifndef EDMONDSKARP_H_
#define EDMONDSKARP_H_
#include "graph.hpp"
#include <vector>
#include <map>
#include <gp-bnb/graph.hpp>
class edmonds_karp {
private:
......@@ -11,8 +11,8 @@ private:
std::map<std::pair<node_id, node_id>, unsigned int> indexed_edges_;
node_id source_;
node_id sink_;
std::vector<node_id> sources_;
std::vector<node_id> sinks_;
int flow_value_;
std::vector<int> flow_;
......@@ -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
* @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.
* @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:
/**
......@@ -37,7 +37,7 @@ public:
* @param source The source 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.
......
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