forked from TheAlgorithms/TypeScript
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathedmonds_karp.ts
97 lines (86 loc) · 2.89 KB
/
edmonds_karp.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
import { StackQueue } from '../data_structures/queue/stack_queue'
/**
* @function edmondsKarp
* @description Compute the maximum flow from a source node to a sink node using the Edmonds-Karp algorithm.
* @Complexity_Analysis
* Time complexity: O(V * E^2) where V is the number of vertices and E is the number of edges.
* Space Complexity: O(E) due to residual graph representation.
* @param {[number, number][][]} graph - The graph in adjacency list form.
* @param {number} source - The source node.
* @param {number} sink - The sink node.
* @return {number} - The maximum flow from the source node to the sink node.
* @see https://en.wikipedia.org/wiki/Edmonds%E2%80%93Karp_algorithm
*/
export default function edmondsKarp(
graph: [number, number][][],
source: number,
sink: number
): number {
const n = graph.length
// Initialize residual graph
const residualGraph: [number, number][][] = Array.from(
{ length: n },
() => []
)
// Build residual graph from the original graph
for (let u = 0; u < n; u++) {
for (const [v, cap] of graph[u]) {
if (cap > 0) {
residualGraph[u].push([v, cap]) // Forward edge
residualGraph[v].push([u, 0]) // Reverse edge with 0 capacity
}
}
}
const findAugmentingPath = (parent: (number | null)[]): number => {
const visited = Array(n).fill(false)
const queue = new StackQueue<number>()
queue.enqueue(source)
visited[source] = true
parent[source] = null
while (queue.length() > 0) {
const u = queue.dequeue()
for (const [v, cap] of residualGraph[u]) {
if (!visited[v] && cap > 0) {
parent[v] = u
visited[v] = true
if (v === sink) {
// Return the bottleneck capacity along the path
let pathFlow = Infinity
let current = v
while (parent[current] !== null) {
const prev = parent[current]!
const edgeCap = residualGraph[prev].find(
([node]) => node === current
)![1]
pathFlow = Math.min(pathFlow, edgeCap)
current = prev
}
return pathFlow
}
queue.enqueue(v)
}
}
}
return 0
}
let maxFlow = 0
const parent = Array(n).fill(null)
while (true) {
const pathFlow = findAugmentingPath(parent)
if (pathFlow === 0) break // No augmenting path found
// Update the capacities and reverse capacities in the residual graph
let v = sink
while (parent[v] !== null) {
const u = parent[v]!
// Update capacity of the forward edge
const forwardEdge = residualGraph[u].find(([node]) => node === v)!
forwardEdge[1] -= pathFlow
// Update capacity of the reverse edge
const reverseEdge = residualGraph[v].find(([node]) => node === u)!
reverseEdge[1] += pathFlow
v = u
}
maxFlow += pathFlow
}
return maxFlow
}