Skip to content

Commit 74f3781

Browse files
committed
feat: implement Johnson's Algorithm for All-Pairs Shortest Paths
1 parent 08d8c6b commit 74f3781

File tree

1 file changed

+89
-0
lines changed

1 file changed

+89
-0
lines changed

Graphs/JohnsonsAlgorithm.js

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
/**
2+
* Johnson's Algorithm for All-Pairs Shortest Paths
3+
* Reference: https://en.wikipedia.org/wiki/Johnson%27s_algorithm
4+
*/
5+
6+
// Helper: Bellman-Ford algorithm
7+
function bellmanFord(graph, source) {
8+
const dist = Array(graph.length).fill(Infinity)
9+
dist[source] = 0
10+
for (let i = 0; i < graph.length - 1; i++) {
11+
for (let u = 0; u < graph.length; u++) {
12+
for (const [v, w] of graph[u]) {
13+
if (dist[u] + w < dist[v]) {
14+
dist[v] = dist[u] + w
15+
}
16+
}
17+
}
18+
}
19+
// Check for negative-weight cycles
20+
for (let u = 0; u < graph.length; u++) {
21+
for (const [v, w] of graph[u]) {
22+
if (dist[u] + w < dist[v]) {
23+
throw new Error('Graph contains a negative-weight cycle')
24+
}
25+
}
26+
}
27+
return dist
28+
}
29+
30+
// Helper: Dijkstra's algorithm
31+
function dijkstra(graph, source) {
32+
const dist = Array(graph.length).fill(Infinity)
33+
dist[source] = 0
34+
const visited = Array(graph.length).fill(false)
35+
for (let i = 0; i < graph.length; i++) {
36+
let u = -1
37+
for (let j = 0; j < graph.length; j++) {
38+
if (!visited[j] && (u === -1 || dist[j] < dist[u])) {
39+
u = j
40+
}
41+
}
42+
if (dist[u] === Infinity) break
43+
visited[u] = true
44+
for (const [v, w] of graph[u]) {
45+
if (dist[u] + w < dist[v]) {
46+
dist[v] = dist[u] + w
47+
}
48+
}
49+
}
50+
return dist
51+
}
52+
53+
54+
export function johnsonsAlgorithm(graph) {
55+
const n = graph.length
56+
57+
const newGraph = graph.map(edges => [...edges])
58+
newGraph.push([])
59+
for (let v = 0; v < n; v++) {
60+
newGraph[newGraph.length - 1].push([v, 0])
61+
}
62+
// Step 1: Run Bellman-Ford from new vertex
63+
const h = bellmanFord(newGraph, n)
64+
// Step 2: Reweight all edges
65+
const reweighted = []
66+
for (let u = 0; u < n; u++) {
67+
reweighted[u] = []
68+
for (const [v, w] of graph[u]) {
69+
reweighted[u].push([v, w + h[u] - h[v]])
70+
}
71+
}
72+
// Step 3: Run Dijkstra from each vertex
73+
const result = []
74+
for (let u = 0; u < n; u++) {
75+
const d = dijkstra(reweighted, u)
76+
result[u] = d.map((dist, v) => dist + h[v] - h[u])
77+
}
78+
return result
79+
}
80+
81+
// Example usage:
82+
// const graph = [
83+
// [[1, 3], [2, 8], [4, -4]],
84+
// [[3, 1], [4, 7]],
85+
// [[1, 4]],
86+
// [[0, 2], [2, -5]],
87+
// [[3, 6]]
88+
// ]
89+
// console.log(johnsonsAlgorithm(graph))

0 commit comments

Comments
 (0)