Leetcode 1584. Min Cost to Connect All Points
Woodyiiiiiii opened this issue · comments
woodyiiiiiii commented
这是一道典型的图基本算法题,包含Prim(用堆优化)和Kruskal(并查集)算法,代码如下:
// Prim
class Solution {
public int minCostConnectPoints(int[][] points) {
return prim(points, 0);
}
public int prim(int[][] points, int start) {
int res = 0;
int n = points.length;
int[][] matrix = new int[n][n];
// 邻接矩阵,方便查询
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
matrix[i][j] = calculate(points, i, j);
matrix[j][i] = matrix[i][j];
}
}
// 访问数组
int[] visited = new int[n];
// 最小距离数组
int[] dis = new int[n];
// 将起始点加入访问数组并更新距离
visited[start] = 1;
dis[start] = -1;
for (int i = 0; i < n; i++) {
if (i != start) {
dis[i] = matrix[start][i];
}
}
// 遍历n - 1次
for (int i = 0; i < n - 1; i++) {
// 找到离最近的一个点的最小距离
int min = Integer.MAX_VALUE;
int index = -1;
for (int j = 0; j < n; j++) {
if (visited[j] == 0 && dis[j] < min) {
min = dis[j];
index = j;
}
}
// 更新
visited[index] = 1;
for (int j = 0; j < n; j++) {
if (visited[j] == 0 && matrix[index][j] < dis[j]) {
dis[j] = matrix[index][j];
}
}
// amass
res += min;
}
return res;
}
public int calculate(int[][] points, int i, int j) {
return Math.abs(points[i][0] - points[j][0]) + Math.abs(points[i][1] - points[j][1]);
}
}
Kruskal + Union find:
// Kruskal + Uninon find
class Solution {
public int minCostConnectPoints(int[][] points) {
int n = points.length;
UnionSet union = new UnionSet(n);
List<Edge> edges = new ArrayList<>();
for (int i = 0; i < n; ++i) {
for (int j = i + 1; j < n; ++j) {
Edge edge = new Edge(i, j, calculate(points, i, j));
edges.add(edge);
}
}
// 排序
Collections.sort(edges, new Comparator<Edge>() {
public int compare(Edge edge1, Edge edge2) {
return edge1.p - edge2.p;
}
});
int ans = 0, cnt = 1;
for (Edge edge : edges) {
int x = edge.x, y = edge.y, p = edge.p;
if (!union.merge(x, y)) {
ans += p;
cnt++;
if (cnt == n) {
break;
}
}
}
return ans;
}
public int calculate(int[][] points, int i, int j) {
return Math.abs(points[i][0] - points[j][0]) + Math.abs(points[i][1] - points[j][1]);
}
}
class UnionSet {
private int n;
private int[] f;
private int[] rank;
public UnionSet(int n) {
this.n = n;
// 设置并查集,一开始每个节点的父节点是本身
f = new int[n];
for (int i = 0; i < n; ++i) {
f[i] = i;
}
// 设置权重
rank = new int[n];
Arrays.fill(rank, 1);
}
// 查询根节点
public int find(int x) {
return f[x] == x ? x : (f[x] = find(f[x]));
}
// 先判断是否在同一集合,不是则集合合并
public boolean merge(int x, int y) {
int fx = find(x), fy = find(y);
if (fx == fy) {
return true;
}
// 找到权重最大的一个
if (rank[fx] < rank[fy]) {
int tmp = fx;
fx = fy;
fy = tmp;
}
rank[fx] += rank[fy];
f[fy] = fx;
return false;
}
}
class Edge {
// 点索引
public int x;
// 另一个点索引
public int y;
// 权
public int p;
public Edge(int x, int y, int p) {
this.x = x;
this.y = y;
this.p = p;
}
}