diff --git a/Graphs/JohnsonsAlgorithm.js b/Graphs/JohnsonsAlgorithm.js new file mode 100644 index 0000000000..ee1b55375c --- /dev/null +++ b/Graphs/JohnsonsAlgorithm.js @@ -0,0 +1,88 @@ +/** + * Johnson's Algorithm for All-Pairs Shortest Paths + * Reference: https://en.wikipedia.org/wiki/Johnson%27s_algorithm + */ + +// Helper: Bellman-Ford algorithm +function bellmanFord(graph, source) { + const dist = Array(graph.length).fill(Infinity) + dist[source] = 0 + for (let i = 0; i < graph.length - 1; i++) { + for (let u = 0; u < graph.length; u++) { + for (const [v, w] of graph[u]) { + if (dist[u] + w < dist[v]) { + dist[v] = dist[u] + w + } + } + } + } + // Check for negative-weight cycles + for (let u = 0; u < graph.length; u++) { + for (const [v, w] of graph[u]) { + if (dist[u] + w < dist[v]) { + throw new Error('Graph contains a negative-weight cycle') + } + } + } + return dist +} + +// Helper: Dijkstra's algorithm +function dijkstra(graph, source) { + const dist = Array(graph.length).fill(Infinity) + dist[source] = 0 + const visited = Array(graph.length).fill(false) + for (let i = 0; i < graph.length; i++) { + let u = -1 + for (let j = 0; j < graph.length; j++) { + if (!visited[j] && (u === -1 || dist[j] < dist[u])) { + u = j + } + } + if (dist[u] === Infinity) break + visited[u] = true + for (const [v, w] of graph[u]) { + if (dist[u] + w < dist[v]) { + dist[v] = dist[u] + w + } + } + } + return dist +} + +export function johnsonsAlgorithm(graph) { + const n = graph.length + + const newGraph = graph.map((edges) => [...edges]) + newGraph.push([]) + for (let v = 0; v < n; v++) { + newGraph[newGraph.length - 1].push([v, 0]) + } + // Step 1: Run Bellman-Ford from new vertex + const h = bellmanFord(newGraph, n) + // Step 2: Reweight all edges + const reweighted = [] + for (let u = 0; u < n; u++) { + reweighted[u] = [] + for (const [v, w] of graph[u]) { + reweighted[u].push([v, w + h[u] - h[v]]) + } + } + // Step 3: Run Dijkstra from each vertex + const result = [] + for (let u = 0; u < n; u++) { + const d = dijkstra(reweighted, u) + result[u] = d.map((dist, v) => dist + h[v] - h[u]) + } + return result +} + +// Example usage: +// const graph = [ +// [[1, 3], [2, 8], [4, -4]], +// [[3, 1], [4, 7]], +// [[1, 4]], +// [[0, 2], [2, -5]], +// [[3, 6]] +// ] +// console.log(johnsonsAlgorithm(graph)) diff --git a/Maths/MobiusFunction.js b/Maths/MobiusFunction.js index bd268b8bbd..4239d6ab31 100644 --- a/Maths/MobiusFunction.js +++ b/Maths/MobiusFunction.js @@ -28,6 +28,6 @@ export const mobiusFunction = (number) => { return primeFactorsArray.length !== new Set(primeFactorsArray).size ? 0 : primeFactorsArray.length % 2 === 0 - ? 1 - : -1 + ? 1 + : -1 } diff --git a/Maths/PollardsRho.js b/Maths/PollardsRho.js new file mode 100644 index 0000000000..72521988c3 --- /dev/null +++ b/Maths/PollardsRho.js @@ -0,0 +1,36 @@ +/** + * Pollard’s Rho Algorithm for Integer Factorization + * + * Pollard’s Rho is a probabilistic algorithm for integer factorization, especially effective for large composite numbers. + * Reference: https://en.wikipedia.org/wiki/Pollard%27s_rho_algorithm + */ + +function gcd(a, b) { + while (b !== 0) { + ;[a, b] = [b, a % b] + } + return a +} + +/** + * Returns a non-trivial factor of n, or n if n is prime + * @param {number} n - Integer to factor + * @returns {number} - A non-trivial factor of n + */ +export function pollardsRho(n) { + if (n % 2 === 0) return 2 + let x = 2, + y = 2, + d = 1, + f = (v) => (v * v + 1) % n + while (d === 1) { + x = f(x) + y = f(f(y)) + d = gcd(Math.abs(x - y), n) + } + return d === n ? n : d +} + +// Example usage: +// const n = 8051; +// console.log(pollardsRho(n)); // Output: a non-trivial factor of 8051