You are given an array points
representing integer coordinates of some points on a 2D-plane, where points[i] = [xi, yi]
.
The cost of connecting two points [xi, yi]
and [xj, yj]
is the manhattan distance between them: |xi - xj| + |yi - yj|
, where |val|
denotes the absolute value of val
.
Return the minimum cost to make all points connected. All points are connected if there is exactly one simple path between any two points.
Example 1:
Input: points = [[0,0],[2,2],[3,10],[5,2],[7,0]] Output: 20 Explanation: We can connect the points as shown above to get the minimum cost of 20. Notice that there is a unique path between every pair of points.
Example 2:
Input: points = [[3,12],[-2,5],[-4,1]] Output: 18
思路:这题跟 1135 Connecting Cities With Minimum Cost 一模一样,就是抽象化的minimum spanning tree, 每次用最小的边去connect graph;Union Find 直觉解决问题;
class Solution {
private class Connection {
public int from;
public int to;
public int cost;
public Connection(int from, int to, int cost) {
this.from = from;
this.to = to;
this.cost = cost;
}
}
private class UnionFind {
private int[] father;
private int size;
public UnionFind(int n) {
this.father = new int[n + 1];
for(int i = 0; i <= n; i++) {
father[i] = i;
}
this.size = n;
}
public int find(int x) {
int j = x;
while(father[j] != j) {
j = father[j];
}
// path compression;
while(x != j) {
int fx = father[x];
father[x] = j;
x = fx;
}
return j;
}
public void union(int a, int b) {
int root_a = find(a);
int root_b = find(b);
if(root_a != root_b) {
father[root_a] = root_b;
size--;
}
}
public int getSize() {
return this.size;
}
}
public int minCostConnectPoints(int[][] points) {
List<Connection> clist = new ArrayList<Connection>();
int n = points.length;
for(int i = 0; i < n; i++) {
for(int j = i + 1; j < n; j++) {
clist.add(new Connection(i, j,
getCost(points[i][0], points[i][1], points[j][0], points[j][1])));
}
}
Collections.sort(clist, (a, b) -> (a.cost - b.cost));
UnionFind uf = new UnionFind(n);
int totalcost = 0;
for(Connection connection: clist) {
int a = connection.from;
int b = connection.to;
int cost = connection.cost;
if(uf.find(a) != uf.find(b)) {
uf.union(a, b);
totalcost += cost;
}
}
return totalcost;
}
private int getCost(int x1, int y1, int x2, int y2) {
return Math.abs(x1 - x2) + Math.abs(y1 - y2);
}
}
思路2: 这题也可以用dijkstra来做,一个node,可以connect到别的node,可以有N条边,那么就是HashMap<Integer, List<Node>> Node里面存 id, cost,然后把所有的neighbor全部丢到priorityqueue里面按照cost sort,然后每次出来都是neighbor cost最小的,visited来收集node的id,这样把每条边都跑完,也就收集到了所有的node id,形成的cost就是最小的visit path cost;
class Solution {
private class Node {
public int index;
public int cost;
public Node(int index, int cost) {
this.index = index;
this.cost = cost;
}
}
public int minCostConnectPoints(int[][] points) {
HashMap<Integer, List<Node>> graph = new HashMap<>();
int n = points.length;
for(int i = 0; i < n; i++) {
for(int j = i + 1; j < n; j++) {
int from = i;
int to = j;
int cost = getCost(points[i][0], points[i][1], points[j][0], points[j][1]);
graph.putIfAbsent(from, new ArrayList<Node>());
graph.putIfAbsent(to, new ArrayList<Node>());
graph.get(from).add(new Node(to, cost));
graph.get(to).add(new Node(from, cost));
}
}
PriorityQueue<Node> pq = new PriorityQueue<Node>((a, b) -> (a.cost - b.cost));
pq.offer(new Node(0, 0));
HashSet<Integer> visited = new HashSet<Integer>();
int totalcost = 0;
while(!pq.isEmpty()) {
Node node = pq.poll();
if(visited.contains(node.index)) {
continue;
}
visited.add(node.index);
totalcost += node.cost;
if(graph.get(node.index) != null) {
for(Node neighbor: graph.get(node.index)) {
if(!visited.contains(neighbor.index)) {
pq.offer(neighbor);
}
}
}
}
return totalcost;
}
private int getCost(int x1, int y1, int x2, int y2) {
return Math.abs(x1 - x2) + Math.abs(y1 - y2);
}
}