给你一个points 数组,表示 2D 平面上的一些点,其中 points[i] = [xi, yi] 。
连接点 [xi, yi] 和点 [xj, yj] 的费用为它们之间的曼哈顿距离 :|xi - xj| + |yi - yj| ,其中 |val| 表示 val 的绝对值。
请你返回将所有点连接的最小总费用。只有任意两点之间 有且仅有 一条简单路径时,才认为所有点都已连接。
示例 1:
输入:points = [[0,0],[2,2],[3,10],[5,2],[7,0]]
输出:20
解释:
我们可以按照上图所示连接所有点得到最小总费用,总费用为 20 。
注意到任意两个点之间只有唯一一条路径互相到达。
示例 2:
输入:points = [[3,12],[-2,5],[-4,1]]
输出:18
示例 3:
输入:points = [[0,0],[1,1],[1,0],[-1,1]]
输出:4
示例 4:
输入:points = [[-1000000,-1000000],[1000000,1000000]]
输出:4000000
示例 5:
输入:points = 0,0
输出:0
提示:
1 <= points.length <= 1000
-106 <= xi, yi <= 106
所有点 (xi, yi) 两两不同。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/min-cost-to-connect-all-points
(1)Kruskal
思路参考Kruskal 最小生成树算法。
//思路1————Kruskal
class Solution {
public int minCostConnectPoints(int[][] points) {
//一共有 n 个节点
int n = points.length;
/*
生成所有边及权重,并用坐标点在 points 中的索引来表示坐标点
int[]{坐标点i, 坐标点j, i 和 j 之间的曼哈顿距离}
*/
List<int[]> edges = new ArrayList<>();
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
int xi = points[i][0];
int yi = points[i][1];
int xj = points[j][0];
int yj = points[j][1];
edges.add(new int[]{i, j, Math.abs(xi - xj) + Math.abs(yi - yj)});
}
}
//将边按照权重进行升序排序
Collections.sort(edges, (a, b) -> {
//返回值为正,则交换 a 和 b
return a[2] - b[2];
});
//Kruskal 算法
int res = 0;
UF uf = new UF(n);
for (int[] edge : edges) {
int u = edge[0];
int v = edge[1];
int weight = edges[2];
//选中的边会产生环,则不能将其加入最小生成树中
if (uf.isConnected(u, v)) {
continue;
}
//如果选中的边不会产生环,则它属于最小生成树
res += weight;
//将节点 u 和 v 进行连通
uf.union(u, v);
}
return res;
}
//并查集
class UF {
//记录连通分量(树)的个数
private int count;
//节点 x 的根节点是 root[x]
private int[] root;
//记录每棵树中的节点数
private int[] size;
//初始化
public UF(int n) {
//初始时每个节点都是一个连通分量
this.count = n;
root = new int[n];
size = new int[n];
for (int i = 0; i < n; i++) {
//初始时每个节点的根节点都是其自己
root[i] = i;
size[i] = 1;
}
}
//将 p 和 q 连通
public void union(int p, int q) {
int rootP = find(p);
int rootQ = find(q);
if (rootP == rootQ) {
// p 和 q 的根节点相同,它们本就是连通的,直接返回即可
return;
} else {
/*
p 和 q 的根节点不相同,将它们连通
小树接到大树下面,这样比较平衡
*/
if (size[rootP] > size[rootQ]) {
root[rootQ] = rootP;
size[rootP] += size[rootQ];
} else {
root[rootP] = rootQ;
size[rootQ] += size[rootP];
}
count--;
}
}
//判断 p 和 q 是否互相连通
public boolean isConnected(int p, int q) {
int rootP = find(p);
int rootQ = find(q);
//如果 p 和 q 的根节点相同,则说明它们在同一颗树上,即它们是连通的
return rootP == rootQ;
}
//查找节点 x 的根节点
public int find(int x) {
while (root[x] != x) {
//进行路径压缩
root[x] = root[root[x]];
x = root[x];
}
return x;
}
//返回连通分量(树)的个数
public int getCount() {
return count;
}
}
}
版权说明 : 本文为转载文章, 版权归原作者所有 版权申明
原文链接 : https://blog.csdn.net/weixin_43004044/article/details/124551067
内容来源于网络,如有侵权,请联系作者删除!