Min Cost to Connect Points

Problem Statement

You are given a 2-D integer array points, where points[i] = [xi, yi]. Each points[i] represents a distinct point on a 2-D plane.

The cost of connecting two points [xi, yi] and [xj, yj] is the manhattan distance between the two points, i.e. $|xi - xj| + |yi - yj|$.

Return the minimum cost to connect all points together, such that there exists exactly one path between each pair of points.

Example 1:

Input: points = [[0,0],[2,2],[3,3],[2,4],[4,2]]
Output: 10

Constraints:

  • 1 <= points.length <= 1000
  • -1000 <= xi, yi <= 1000

You should aim for a solution as good or better than O(n^2 \log n) time and O(n^2) space, where n is the number of points.

You should aim for a solution as good or better than O(n^2 \log n) time and O(n^2) space, where n is the number of points.

Hint 1

Think of this problem as a graph, where the given points represent nodes. We need to connect these nodes into a single component by creating edges. Can you think of an advanced graph algorithm that can be used to connect all points into one component?

Hint 2

We use Kruskal’s algorithm along with Union-Find (DSU) to connect nodes into components. The final component forms the minimum spanning tree (MST), where the edges between nodes are weighted by the Manhattan distance, and the total weight of the tree is minimized. How would you implement this?

Hint 3

We create the possible edges by iterating through every pair of points and calculating the weights as the Manhattan distance between them. Next, we sort the edges in ascending order based on their weights, as we aim to minimize the cost. Then, we traverse through these edges, connecting the nodes and adding the weight of the edge to the total cost if the edge is successfully added. The final result will be the minimum cost.

Solution

Kruskal’s Algorithm

class DSU:
def __init__(self, n):
self.parent = list(range(n + 1))
self.size = [1] * (n + 1)
def find(self, node):
if self.parent[node] != node:
self.parent[node] = self.find(self.parent[node])
return self.parent[node]
def union(self, u, v):
pu = self.find(u)
pv = self.find(v)
if pu == pv:
return False
if self.size[pu] < self.size[pv]:
pu, pv = pv, pu
self.size[pu] += self.size[pv]
self.parent[pv] = pu
return True
def min_cost_connect_points(points: list[list[int]]) -> int:
n = len(points)
dsu = DSU(n)
edges = []
for i in range(n):
x1, y1 = points[i]
for j in range(i + 1, n):
x2, y2 = points[j]
dist = abs(x1 - x2) + abs(y1 - y2)
edges.append((dist, i, j))
edges.sort()
result = 0
for dist, u, v in edges:
if dsu.union(u, v):
result += dist
return result

Time complexity: O(n^2 \log n) Space complexity: O(n^2)