Algoteka
Log in to submit your own samples!

Ford-Fulkerson Algorithm

Problem by oml1111
# Tech tags Title Creator Created date
1 0
2022-10-13 18:54
View all samples for this language (1 verified and 0 unverified)

Readable Recursive Solution | C++ |

By oml1111 |
0 likes

An \(O(|E|F)\) implementation of Ford-Fulkerson algorithm (\(|E|\) is the number of edges and \(F\) is the maximum flow). Focuses on simplicity and readability and uses no external libraries.

Caveat: The depth-first-search algorithm is recursive, which means the function calls get stored in the call stack. The maximum call-stack size is usually 1MB on Windows and 10MB on Linux, which means the program might crash if the depth of the recursion gets large and if you don't set the stack size to be larger.

Code

#include<iostream>
#include<vector>
#include<deque>
#include<limits>
#include<algorithm>


struct FordFulkersonGraph {
    struct Arc {
        int start_;
        int end_;
        int flow_;
        int capacity_;
        
        int get_dest(int from) {  // Return the destination node if we were to traverse the arc from node `from`
            if(from == start_) {
                return end_;
            } else {
                return start_;
            }
        }
        
        void add_flow(int from, int to_add) {  // Adds flow from originating vertex `from`
            if(from == start_) {
                flow_ += to_add;
            } else {
                flow_ -= to_add;
            }
        }
        
        int get_capacity(int from) {  // Gets the capacity of the edge if the originating vertex is `from`
            if(from == start_) {
                return capacity_ - flow_;
            } else {
                return flow_;
            }
        }
    };
    
    struct Node {
        int index;
        std::vector<Arc*> connected_arcs_;  // Arcs (directed edges) that start and end in this node
    };
    
    std::vector<Node> nodes_;
    std::deque<Arc> arcs_;  // We use deque here to prevent pointer invalidation on reallocation
    
    void add_node() {
        nodes_.push_back({(int)nodes_.size(), {}});
    }
    
    void add_edge(int start, int end, int capacity) {
        arcs_.push_back({start, end, 0, capacity});
        nodes_[start].connected_arcs_.push_back(&arcs_.back());
        nodes_[end].connected_arcs_.push_back(&arcs_.back());
    }
    
    int _push_augmenting_path_dfs(int pos, int end, int to_push, std::vector<bool> *explr = NULL) {
        if(explr == NULL) {
            explr = new std::vector<bool>(nodes_.size(), false);
        }
        if(pos == end) {
            return to_push;
        }
        
        explr->at(pos) = true;
        for(Arc* arc : nodes_[pos].connected_arcs_) {
            int dest = arc->get_dest(pos);
            int arc_capacity = arc->get_capacity(pos);
            if(!explr->at(dest) && arc_capacity > 0) {
                // Recursively find if we can push flow through any of the connected nodes
                int amount_pushed = _push_augmenting_path_dfs(dest, end, std::min(arc_capacity, to_push), explr);
                if(amount_pushed > 0) {
                    arc->add_flow(pos, amount_pushed);
                    return amount_pushed;
                }
            }
        }
        return 0;  // Failed to push flow towards destination in any direction
    }
    
    int compute_flow(int start, int end) {
        int result = 0;
        int amount_pushed;
        do {
            amount_pushed = _push_augmenting_path_dfs(start, end, std::numeric_limits<int>::max());
            result += amount_pushed;
        } while(amount_pushed > 0);
        return result;
    }
};


int main() {
    // Construct a simple flow network and find the max-flow on it
    FordFulkersonGraph graph;
    for(int i=0; i<6; i++) graph.add_node();
    graph.add_edge(0, 1, 2);
    graph.add_edge(1, 4, 2);
    graph.add_edge(4, 5, 2);
    graph.add_edge(1, 2, 1);
    graph.add_edge(2, 5, 1);
    graph.add_edge(0, 3, 1);
    graph.add_edge(3, 4, 1);
    int result = graph.compute_flow(0, 4);
    std::cout << result << '\n';
    return 0;
}

Further reading

Maximum Flow: Ford-Fulkerson method - cp-algorithms.com

References

objects
std::cout en.cppreference.com cplusplus.com
classes
std::deque en.cppreference.com cplusplus.com
std::numeric_limits en.cppreference.com cplusplus.com
std::vector en.cppreference.com cplusplus.com
functions
std::basic_ostream::operator<< en.cppreference.com cplusplus.com
std::deque::back en.cppreference.com cplusplus.com
std::deque::push_back en.cppreference.com cplusplus.com
std::max en.cppreference.com cplusplus.com
std::numeric_limits::max en.cppreference.com
std::vector::at en.cppreference.com cplusplus.com
std::vector::operator[] en.cppreference.com cplusplus.com
std::vector::push_back en.cppreference.com cplusplus.com
std::vector::vector en.cppreference.com cplusplus.com

Problem Description

Implement the Ford-Fulkerson max-flow algorithm. Construct some example flow network and find the maximum-flow on it.

Ford–Fulkerson algorithm - wikipedia.org
Flow network - wikipedia.org

View sample discussion (0 comments)
View problem discussion (0 comments)