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