From dfd743f50c00a44741e063ccfd2f7807cd67cb3c Mon Sep 17 00:00:00 2001 From: Lukas Garbas <lukasgarba@gmail.com> Date: Tue, 14 May 2019 10:40:28 +0200 Subject: [PATCH] multiple sources and sinks --- bnb/edmonds_karp.cpp | 78 ++++++++++++++++++++------------- include/gp-bnb/edmonds_karp.hpp | 12 ++--- 2 files changed, 53 insertions(+), 37 deletions(-) diff --git a/bnb/edmonds_karp.cpp b/bnb/edmonds_karp.cpp index 90c307b..b35a000 100644 --- a/bnb/edmonds_karp.cpp +++ b/bnb/edmonds_karp.cpp @@ -1,13 +1,12 @@ #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 { diff --git a/include/gp-bnb/edmonds_karp.hpp b/include/gp-bnb/edmonds_karp.hpp index 95616fa..86e3f12 100644 --- a/include/gp-bnb/edmonds_karp.hpp +++ b/include/gp-bnb/edmonds_karp.hpp @@ -1,9 +1,9 @@ #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. -- GitLab