Network Flow Algorithm
Разница между en1 и en2, 197 символ(ов) изменены
Hey everyone! <br>↵

We were taught basic network flow in our algorithms course in university and I started to learn it. Found this useful blog↵
blog by [user:Zhtluo,2025-10-21] [link](https://mirror.codeforces.com/blog/entry/141680)↵

### Target Audience.↵
This post is for anyone who has some free time :)<br>↵

<spoiler summary="Help if you can spare some time">↵
To do the first kind of problems Graph Matching. I went through William Fiset’s amazing YouTube playlist on Network Flow↵
Since I learned it all from one source, I wanted to write this blog to share what I understood — and more importantly — to ask the community for new perspectives and interesting problems to explore using this algorithm. <br>↵
</spoiler>↵

### Basic↵

<spoiler summary="What is network flow">↵
Imagine you have a water system:<br><br>↵
A big tank (source) that sends water to↵
A fountain (sink) through↵
Several pipes (edges) connected by junctions (nodes). <br><br>↵
Each pipe has a limit — called capacity — which represents how much water it can carry. <br><br>↵
![ ](https://i.ibb.co/5Wb6PnJQ/Screenshot-2025-10-21-233818.png) <br>↵
Our goal?↵
➡️ Find the maximum amount of water that can flow from the tank (source) to the fountain (sink). <br><br>↵
</spoiler>↵

### Bipartite Matching Example↵
Suppose we have two sets: <br>↵
Set A = people↵
Set B = books <br><br>↵

Each person likes certain books, and we want to find the maximum number of unique person-book matches, where each person gets exactly one book they like. <br><br>↵
Here’s how Network Flow helps:↵
Connect the source to all people.↵
Connect each person to the books they like.↵
Connect all books to the sink. <br><br>↵

Then, when we run a maximum flow algorithm, the maximum flow value will tell us the number of unique person-book pairs that can be matched. <br>↵
This is basically the maximum bipartite matching problem. <br><br>↵
![ ](https://i.ibb.co/TDr4g5MN/Screenshot-2025-10-21-224315.png)↵
The Ford–Fulkerson Algorithm↵
------------------↵
We keep finding paths from the source to the sink that still have some remaining capacity, and push as much flow as possible through them — until no such paths exist. <br><br>↵
### Steps↵
1. Use DFS to find a path from source to sink.↵

2. Find the smallest capacity (bottleneck) along that path.↵

3. Send that much “water” (flow) through the path.↵

4. Add a reverse edge to allow undoing flow later.↵

5. Repeat until no more augmenting paths exist. <br><br>↵

### Time Complexity↵
O(E × f) where f is the value of the maximum flow. <br><br>↵

### Code↵

<spoiler summary="Code">↵

~~~~~↵
typedef struct{↵
    int to;↵
    int flow;↵
    int capacity;↵
    int rev; // index of reverse edge↵
}edge;↵

int source;↵
int sink;↵
vector<vector<edge>> adj;↵

void addedge(int from, int to, int cap){↵
    adj[from].push_back({to, 0, cap, (int)adj[to].size()});↵
    adj[to].push_back({from, 0, 0, (int)adj[from].size() - 1}); // reverse edge↵
}↵

int dfs(int curr, vector<bool> & visited, int bottleneck){↵
    if(curr == sink){↵
        return bottleneck;↵
    }↵
    visited[curr] = true;↵
    ↵
    for (int i = 0; i < adj[curr].size(); i++){↵
        edge &e = adj[curr][i];↵
        if(!visited[e.to] && e.capacity - e.flow > 0){↵
            int flow = dfs(e.to, visited, min(bottleneck, e.capacity - e.flow));↵
            if(flow > 0){↵
                e.flow += flow;↵
                adj[e.to][e.rev].flow -= flow; // update reverse edge↵
                return flow;↵
            }↵
        }↵
    }↵
    return 0;↵
}↵

int fordFulkerson(){↵
    int maxflow = 0;↵
    while(true){↵
        vector<bool> visited(adj.size(), false);↵
        int flow = dfs(source, visited, INT_MAX);↵
        if(flow == 0) break;↵
        maxflow += flow;↵
    }↵
    return maxflow;↵
}↵
~~~~~↵
...↵
</spoiler>


It’s conceptually simple but can be slow if the capacities are large because runtime depends directly on the flow value. <br><br>↵

The Edmonds–Karp Algorithm↵
------------------↵
This is an optimized version of Ford–Fulkerson that uses BFS instead of DFS to find augmenting paths. <br><br>↵
Why BFS?↵
Using DFS can lead to zig-zagging paths that push very little flow each time, making the algorithm slow.↵
BFS ensures we always find the shortest path (in terms of number of edges), which makes the process much more efficient. <br><br>↵
### Steps↵
1. Use BFS to find the shortest augmenting path.↵

2. Find the bottleneck capacity on that path.↵

3. Push flow along the path and update reverse edges.↵

4. Repeat until no more augmenting paths exist. <br><br>↵

### Time Complexity↵
O(V × E²) <br><br>↵
This guarantees a polynomial runtime↵

### Code↵

<spoiler summary="Code">↵
~~~~~↵
typedef struct{↵
    int to;↵
    int flow;↵
    int capacity;↵
    int rev; // index of reverse edge↵
}edge;↵
int source;↵
int sink;↵
vector<vector<edge>> adj;↵
void addedge(int from, int to, int cap){↵
    adj[from].push_back({to, 0, cap, (int)adj[to].size()});↵
    adj[to].push_back({from, 0, 0, (int)adj[from].size() - 1}); // reverse edge↵
}↵
int bfs(vector<int> &parent){↵
    vector<bool> visited(adj.size(), false);↵
    queue<int> q;↵
    q.push(source);↵
    visited[source] = true;↵
    parent[source] = -1;↵

    while(!q.empty()){↵
        int curr = q.front();↵
        q.pop();↵

        for (int i = 0; i < adj[curr].size(); i++){↵
            edge &e = adj[curr][i];↵
            if(!visited[e.to] && e.capacity - e.flow > 0){↵
                q.push(e.to);↵
                parent[e.to] = curr;↵
                visited[e.to] = true;↵
                if(e.to == sink) return 1;↵
            }↵
        }↵
    }↵
    return 0;↵
}↵
int edmondsKarp(){↵
    int maxflow = 0;↵
    vector<int> parent(adj.size());↵

    while(bfs(parent)){↵
        int flow = INT_MAX;↵
        for(int v = sink; v != source; v = parent[v]){↵
            int u = parent[v];↵
            flow = min(flow, adj[u][v].capacity - adj[u][v].flow);↵
        }↵
        for(int v = sink; v != source; v = parent[v]){↵
            int u = parent[v];↵
            adj[u][v].flow += flow;↵
            adj[v][adj[u][v].rev].flow -= flow; // update reverse edge↵
        }↵

        maxflow += flow;↵
    }↵
    return maxflow;↵
}↵
~~~~~↵
...↵
</spoiler>


### PRACTICE PROBLEMS↵
1. [Katis Elementary math](https://open.kattis.com/problems/elementarymath)↵
2. [Katis Gopher2](https://open.kattis.com/problems/gopher2)↵
3. [CF Delivery Bears](https://mirror.codeforces.com/contest/653/problem/D)↵
4. [ICPC regionals I. Magic Potions](https://mirror.codeforces.com/gym/101981/attachments)



Again, if possible, please provide new perspectives and interesting problems to explore using this algorithm

История

 
 
 
 
Правки
 
 
  Rev. Язык Кто Когда Δ Комментарий
en2 Английский deinepapa 2025-10-21 21:23:10 197 (published)
en1 Английский deinepapa 2025-10-21 21:19:44 6519 Initial revision (saved to drafts)