Build a minimum spanning tree on a complete graph where edge weights are Manhattan distances. Run Prim's algorithm with a min-heap: always grow the tree by the cheapest available edge, skipping nodes already inside.
Given n points on a 2-D plane, connect them all with the minimum total cost. The cost of connecting two points is their Manhattan distance: |x1 - x2| + |y1 - y2|. Each point must be reachable from every other (one connected component), and there are no required intermediate stops.
Worked example. points = [[0,0],[2,2],[3,10],[5,2],[7,0]]. The optimal MST uses edges with costs 4, 3, 5, and 6, totalling 20.
O(log n).[cost=0, node=0]— zero cost to “include the starting node itself”.[cost, u] from the heap. If u is already in the MST, this is a stale entry — skip it with continue.u as in the MST, add cost to the running total. Increment the edge/node counter — stop when all n nodes are committed.v, compute the Manhattan distance from u to v and push [d, v]to the heap if it's cheaper than what we've seen before (optional optimisation — or push unconditionally and let the skip in step 1 handle duplicates).totalCost.if (inMST[u]) continueguard in step 1 silently drops these stale pops — forget it and you'll add costs multiple times and loop forever.Kruskal's algorithm sorts all O(n²) edges then applies Union-Find: O(n² log n)— same asymptotic but more memory. Kruskal shines when the graph is sparse; on this dense complete graph Prim's with an array-based “min edge” scan is actually O(n²) and preferred in practice.
0. Seed min-heap with [cost=0, node=0].1function minCostConnectPoints(points: number[][]): number {2▶ const n = points.length;3 if (n <= 1) return 0;45 // inMST[i] = true once node i has been added to the spanning tree6▶ const inMST = new Array<boolean>(n).fill(false);78 // minEdge[i] = cheapest known edge cost to connect node i into the MST9▶ const minEdge = new Array<number>(n).fill(Infinity);10▶ minEdge[0] = 0; // start from node 0 at cost 01112 // Min-heap entries: [cost, nodeIndex]13 // Using a simple array-based binary heap14▶ const heap: [number, number][] = [[0, 0]];15▶ let totalCost = 0;16▶ let edgesAdded = 0;1718 const heapPush = (cost: number, node: number): void => {19 heap.push([cost, node]);20 let i = heap.length - 1;21 while (i > 0) {22 const p = (i - 1) >> 1;23 if (heap[p][0] <= heap[i][0]) break;24 [heap[p], heap[i]] = [heap[i], heap[p]];25 i = p;26 }27 };2829 const heapPop = (): [number, number] => {30 const top = heap[0];31 const last = heap.pop()!;32 if (heap.length > 0) {33 heap[0] = last;34 let i = 0;35 while (true) {36 const l = 2 * i + 1, r = 2 * i + 2;37 let s = i;38 if (l < heap.length && heap[l][0] < heap[s][0]) s = l;39 if (r < heap.length && heap[r][0] < heap[s][0]) s = r;40 if (s === i) break;41 [heap[i], heap[s]] = [heap[s], heap[i]];42 i = s;43 }44 }45 return top;46 };4748 while (heap.length > 0 && edgesAdded < n) {49 const [cost, u] = heapPop();5051 if (inMST[u]) continue; // stale heap entry — skip52 inMST[u] = true;53 totalCost += cost;54 edgesAdded++;5556 for (let v = 0; v < n; v++) {57 if (!inMST[v]) {58 const d = Math.abs(points[u][0] - points[v][0])59 + Math.abs(points[u][1] - points[v][1]);60 if (d < minEdge[v]) {61 minEdge[v] = d;62 heapPush(d, v);63 }64 }65 }66 }6768 return totalCost;69}
function minCostConnectPoints(points: number[][]): number {
const n = points.length;
if (n <= 1) return 0;
// inMST[i] = true once node i has been added to the spanning tree
const inMST = new Array<boolean>(n).fill(false);
// minEdge[i] = cheapest known edge cost to connect node i into the MST
const minEdge = new Array<number>(n).fill(Infinity);
minEdge[0] = 0; // start from node 0 at cost 0
// Min-heap entries: [cost, nodeIndex]
// Using a simple array-based binary heap
const heap: [number, number][] = [[0, 0]];
let totalCost = 0;
let edgesAdded = 0;
const heapPush = (cost: number, node: number): void => {
heap.push([cost, node]);
let i = heap.length - 1;
while (i > 0) {
const p = (i - 1) >> 1;
if (heap[p][0] <= heap[i][0]) break;
[heap[p], heap[i]] = [heap[i], heap[p]];
i = p;
}
};
const heapPop = (): [number, number] => {
const top = heap[0];
const last = heap.pop()!;
if (heap.length > 0) {
heap[0] = last;
let i = 0;
while (true) {
const l = 2 * i + 1, r = 2 * i + 2;
let s = i;
if (l < heap.length && heap[l][0] < heap[s][0]) s = l;
if (r < heap.length && heap[r][0] < heap[s][0]) s = r;
if (s === i) break;
[heap[i], heap[s]] = [heap[s], heap[i]];
i = s;
}
}
return top;
};
while (heap.length > 0 && edgesAdded < n) {
const [cost, u] = heapPop();
if (inMST[u]) continue; // stale heap entry — skip
inMST[u] = true;
totalCost += cost;
edgesAdded++;
for (let v = 0; v < n; v++) {
if (!inMST[v]) {
const d = Math.abs(points[u][0] - points[v][0])
+ Math.abs(points[u][1] - points[v][1]);
if (d < minEdge[v]) {
minEdge[v] = d;
heapPush(d, v);
}
}
}
}
return totalCost;
}inMST tracks which nodes are committed. minEdge caches the cheapest known edge into each node (used as an optional pruning guard). Seed the heap with [cost=0, node=0]— zero because we pay nothing to “reach the starting point from itself”.heapPush appends and bubbles up; heapPop swaps the root with the last element and sifts down. The invariant: heap[parent][0] ≤ heap[child][0] (min by cost).if (inMST[u]) continue check is the core of the lazy-deletion pattern: once a node is committed, any later pops for it are discarded.u as in the MST, accumulate its edge cost, and increment edgesAdded. We stop as soon as all n nodes are added (a spanning tree on n nodes has exactly n-1 edges, but counting nodes is equivalent).v, compute |x_u - x_v| + |y_u - y_v|, and push if it improves the best known cost for v. The if (d < minEdge[v]) guard avoids redundant heap entries and keeps the heap lean; it is optional but speeds up dense inputs.minEdge[n] and do a linear scan to find the next cheapest node each round. Eliminates heap overhead; ideal for dense graphs.O(n²)edges materialised and sorted first. Prim's discovers edges lazily, so memory stays O(n) (plus the heap).n^(n-2)by Cayley's formula) and pick the minimum. Hopeless for n > 10.| "connect all points / nodes with minimum total cost" | Prim's or Kruskal's MST |
| complete graph (every pair can connect) | Prim's with min-heap — no need to materialise all edges |
| growing a set greedily, always cheapest next | min-heap + inMST visited set |
| 2-D points, Manhattan or Euclidean distance | MST with inline distance formula |
const n = points.length;
const inMST = new Array<boolean>(n).fill(false);
const heap: [number, number][] = [[0, 0]]; // [cost, node]
let totalCost = 0, edgesAdded = 0;
while (heap.length > 0 && edgesAdded < n) {
const [cost, u] = heapPop();
if (inMST[u]) continue;
inMST[u] = true;
totalCost += cost;
edgesAdded++;
for (let v = 0; v < n; v++) {
if (!inMST[v]) heapPush(manhattan(u, v), v);
}
}
return totalCost;points = [[0,0],[2,2],[3,10],[5,2],[7,0]]. What does the algorithm return?[1,3] and [4,7] is: