Data Structures and Algorithms in Java
GitHubAuthor
  • Preface
    • Syllabus
    • Schedule
  • 0. Getting Started
    • 0.1. Environment Setup
    • 0.2. Quiz
  • 1. Java Essentials
    • 1.1. Abstraction
    • 1.2. Implementation
    • 1.3. Unit Testing
    • 1.4. Quiz
  • 2. Priority Queues
    • 2.1. Simple Priority Queues
    • 2.2. Binary Heap
    • 2.3. Unit Testing
    • 2.4. Benchmarking
    • 2.5. Quiz
  • 3. Sorting Algorithms
    • 3.1. Abstraction
    • 3.2. Comparison-based Sort
    • 3.3. Divide & Conquer Sort
    • 3.4. Distribution-based Sort
    • 3.5. Quiz
    • 3.6. Homework
  • 4. Binary Search Trees
    • 4.1. Binary Search Trees
    • 4.2. Balanced BST
    • 4.2. AVL Trees
    • 4.3. Red-Black Trees
    • 4.4. Quiz
  • 5. Tries
    • 5.1. Concept
    • 5.2. Implementation
    • 5.3. Quiz
    • 5.4. Homework
  • 6. Disjoint Sets
    • 6.1. Concept
    • 6.2. Implementation
    • 6.3. Quiz
  • 7. Graphs
    • 7.1. Implementation
    • 7.2. Cycle Detection
    • 7.3. Topological Sorting
    • 7.4. Quiz
  • 8. Minimum Spanning Trees
    • 8.1. Abstraction
    • 8.2. Prim's Algorithm
    • 8.3. Kruskal’s Algorithm
    • 8.4. Edmonds' Algorithm
    • 8.5. Quiz
    • 8.6. Homework
  • 9. Network Flow
    • 9.1. Flow Network
    • 9.2. Ford-Fulkerson Algorithm
    • 9.3. Simplex Algorithm
    • 9.3. Quiz
  • 10. Dynamic Programming
    • 10.1. Fibonacci Sequence
    • 10.2. Tower of Hanoi
    • 10.3. Longest Common Subsequence
    • 10.4. Quiz
Powered by GitBook

©2023 Emory University - All rights reserved

On this page
  • Subgraph
  • Ford-Fulkerson
  • Backward Pushing

Was this helpful?

Export as PDF
  1. 9. Network Flow

9.2. Ford-Fulkerson Algorithm

This section describes the implementation of Ford-Fulkerson Algorithm

Previous9.1. Flow NetworkNext9.3. Simplex Algorithm

Last updated 4 years ago

Was this helpful?

Subgraph

Let us define the class that consists of a subset of vertices and edges from the original graph:

public class Subgraph {
    private final List<Edge> edges;
    private final Set<Integer> vertices;

    public Subgraph() {
        edges = new ArrayList<>();
        vertices = new HashSet<>();
    }

    public Subgraph(Subgraph graph) {
        edges = new ArrayList<>(graph.getEdges());
        vertices = new HashSet<>(graph.getVertices());
    }
}

Let us define helper methods:

public List<Edge> getEdges() { return edges; }

public Set<Integer> getVertices() { return vertices; }

public void addEdge(Edge edge) {
    edges.add(edge);
    vertices.add(edge.getSource());
    vertices.add(edge.getTarget());
}

public boolean contains(int vertex) {
    return vertices.contains(vertex);
}

Ford-Fulkerson

Ford-Fulkerson algorithm finds the maximum flow from a flow network as follows:

public class FordFulkerson implements NetworkFlow {
    public MaxFlow getMaximumFlow(Graph graph, int source, int target) {
        MaxFlow mf = new MaxFlow(graph);
        Subgraph sub;

        while ((sub = getAugmentingPath(graph, mf, new Subgraph(), source, target)) != null) {
            double min = getMin(mf, sub.getEdges());
            mf.updateFlow(sub.getEdges(), min);
        }

        return mf;
    }
}
public class FordFulkerson implements NetworkFlow {
    public MaxFlow getMaximumFlow(Graph graph, int source, int target) {
        MaxFlow mf = new MaxFlow(graph);
        Subgraph sub;

        while ((sub = getAugmentingPath(graph, mf, new Subgraph(), source, target)) != null) {
            double min = getMin(mf, sub.getEdges());
            mf.updateFlow(sub.getEdges(), min);
            updateBackward(graph, sub, mf, min);
        }

        return mf;
    }
}
  • L2: indicates one source and one target vertices.

  • L6: iterates as long as it can find an augmenting path

    • L7: finds the edge with the minimum capacity in the augmenting path.

    • L8: updates the edges in the path with the flow.

Let us define the getMin() method:

private double getMin(MaxFlow mf, List<Edge> path) {
    double min = mf.getResidual(path.get(0));

    for (int i = 1; i < path.size(); i++)
        min = Math.min(min, mf.getResidual(path.get(i)));

    return min;
}

Finally, let us define the getAugmentingPath() method:

private Subgraph getAugmentingPath(Graph graph, MaxFlow mf, Subgraph sub, int source, int target) {
    if (source == target) return sub;
    Subgraph tmp;

    for (Edge edge : graph.getIncomingEdges(target)) {
        if (sub.contains(edge.getSource())) continue;
        if (mf.getResidual(edge) <= 0) continue;
        tmp = new Subgraph(sub);
        tmp.addEdge(edge);
        tmp = getAugmentingPath(graph, mf, tmp, source, edge.getSource());
        if (tmp != null) return tmp;
    }

    return null;
}
  • L2: once the source reaches the target, it found an augmenting path.

  • L6: adding the source vertex would cause a cycle.

  • L7: cannot push the flow when there is no residual left.

  • L10: recursively finds the augmenting path by switching the target.

Backward Pushing

Let us consider the following graph:

As shown, our implementation of Ford-Fulkerson Algorithm does not always guarantee to find the maximum flow correctly. To fix this issue, we need to implement backward pushing:

The backward pushing can be performed after the applying the flow to all edges as in the implementation above (see the code in the "With Backward Pushing" tab).

Finally, the updateBackward() method can be implemented as follows:

protected void updateBackward(Graph graph, Subgraph sub, MaxFlow mf, double min) {
    boolean found;

    for (Edge edge : sub.getEdges()) {
        found = false;

        for (Edge rEdge : graph.getIncomingEdges(edge.getSource())) {
            if (rEdge.getSource() == edge.getTarget()) {
                mf.updateFlow(rEdge, -min);
                found = true;
                break;
            }
        }

        if (!found) {
            Edge rEdge = graph.setDirectedEdge(edge.getTarget(), edge.getSource(), 0);
            mf.updateFlow(rEdge, -min);
        }
    }
}

Let us create the class:

Subgraph
FordFulkerson