题目
给你一个points 数组,表示 2D 平面上的一些点,其中 points[i] = [xi, yi] 。
连接点 [xi, yi] 和点 [xj, yj] 的费用为它们之间的 曼哈顿距离 :|xi - xj| + |yi - yj| ,其中 |val| 表示 val 的绝对值。
请你返回将所有点连接的最小总费用。只有任意两点之间 有且仅有 一条简单路径时,才认为所有点都已连接。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/min-cost-to-connect-all-points
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
代码
class Solution {
public int minCostConnectPoints(int[][] points) {
int n = points.length;
// 生成所有边及权重
ArrayList<int[]> edges = new ArrayList<>();//用于存两点间的距离
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
int xi = points[i][0], yi = points[i][1];
int xj = points[j][0], yj = points[j][1];
// 用坐标点在 points 中的索引表示坐标点
edges.add(new int[]{
i, j, Math.abs(xi - xj) + Math.abs(yi - yj) //记录i到j的距离
});
}
}
// 将边按照权重从小到大排序
Collections.sort(edges, new Comparator<int[]>() {
@Override
public int compare(int[] o1, int[] o2) {
return o1[2] - o2[2];
}
});
// 执行 Kruskal 算法
int mst = 0;
UF uf = new UF(n);
for (int[] edge : edges
) {
int u = edge[0];
int v = edge[1];//u→v
int weight = edge[2];
// 若这条边会产生环,则不能加入 mst
if (uf.connected(u, v)) continue;
// 若这条边不会产生环,则属于最小生成树
mst += weight;
uf.union(u, v);
}
return mst;
}
//并查集
class UF {
// 记录连通分量个数
private int count;
// 存储若干棵树的父节点
private int[] parent;
// 记录树的“重量”
private int[] size;
public UF(int n) {
this.count = n;
parent = new int[n];
size = new int[n];
for (int i = 0; i < n; i++) {
parent[i] = i;//每个父节点都是自己
size[i] = 1;//每棵树大小都为1
}
}
/* 将 p 和 q 连通 */
public void union(int p, int q) {
int rootP = find(p);
int rootQ = find(q);
if (rootP == rootQ) return;//本来就连通
// 小树接到大树下面,较平衡
if (size[rootP] > size[rootQ]) {
parent[rootQ] = rootP;
size[rootP] += size[rootQ];
} else {
parent[rootP] = rootQ;
size[rootQ] += size[rootP];
}
count--;//连通分量减小
}
/* 判断 p 和 q 是否互相连通 */
public boolean connected(int p, int q) {
int rootP = find(p);
int rootQ = find(q);
// 处于同一棵树上的节点,相互连通
return rootP == rootQ;
}
/* 返回节点 x 的根节点 */
private int find(int x) {
while (parent[x] != x) {
//顺便进行路径压缩
parent[x] = parent[parent[x]];
x = parent[x];
}
return x;
}
public int count() {//返回连通分量
return count;
}
}
}
要点
- 使用kruskal算法,树的判定算法加上按权重排序的逻辑就变成了 Kruskal 算法
- 树判定算法通过并查集来实现:若两个顶点有同一根结点,则成环