1584. 连接所有点的最小费用(kruaskal+prim求最小生成树)

1584. 连接所有点的最小费用

给你一个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) 两两不同。

方法一(kruaskal算法):

复制代码
 1 class UnionFindSet {
 2 public:
 3     void init(int n) {
 4         parent.resize(n);
 5         rank.resize(n);
 6         for (int i = 0; i < n; i++) {
 7             parent[i] = i;
 8             rank[i] = 1;
 9         }
10     }
11     int findRoot(int x) {
12         if (x == parent[x]) {
13             return x;
14         }
15         parent[x] = findRoot(parent[x]);
16         return parent[x];
17     }
18     bool isConnected(int x, int y) {
19         return (findRoot(x) == findRoot(y));
20     }
21     void unify(int x, int y) {
22         if (isConnected(x, y)) {
23             return;
24         }
25         int xRoot = findRoot(x);
26         int yRoot = findRoot(y);
27         if (rank[xRoot] > rank[yRoot]) {
28             parent[yRoot] = xRoot;
29         } else if (rank[xRoot] < rank[yRoot]) {
30             parent[xRoot] = yRoot;
31         } else {
32             parent[xRoot] = yRoot;
33             rank[yRoot]++;
34         }
35         return;
36     }
37 private:
38     vector<int> parent;
39     vector<int> rank;
40 };
41 
42 class Solution : public UnionFindSet {
43 public:
44     int getCost(vector<int> point1, vector<int> point2) {
45         return (abs(point1[0] - point2[0]) + abs(point1[1] - point2[1]));
46     }
47     int minCostConnectPoints(vector<vector<int>>& points) {
48         if (points.size() == 0 || points[0].size() == 0) {
49             return 0;
50         }
51         vector<vector<int>> graph;
52         int row = points.size();
53         // 初始化并查集
54         init(row);
55         // 构建图
56         for (int i = 0; i < row - 1; i++) {
57             for (int j = i + 1; j < row; j++) {
58                 int cost = getCost(points[i], points[j]);
59                 graph.push_back({i, j, cost}); // 边i->边j花费cost
60             }
61         }
62         // 按照花费对图进行升序排序
63         sort(graph.begin(), graph.end(), [](const vector<int> &a, const vector<int> &b) {
64             return a.back() < b.back();
65         });
66         int ans = 0;
67         int cnt = 0;
68         for (auto &vec : graph) {
69             // 如果连接边的个数达到N-1(N为顶点个数),怎找到最小生成树
70             if (cnt == row - 1) {
71                 break;
72             }
73             // 如果待连接的两个点已经连通,即如果再连接的话就会形成环,则跳过
74             if (isConnected(vec[0], vec[1])) {
75                 continue;
76             }
77             unify(vec[0], vec[1]);
78             ans += vec[2];
79             cnt++;
80         }
81         return ans;
82     }
83 };
复制代码

 

方法二(prim算法):

复制代码
 1 struct Edge {
 2     Edge(int p1, int p2, int distance) {
 3         point1 = p1;
 4         point2 = p2;
 5         cost = distance;
 6     }
 7     int point1;
 8     int point2;
 9     int cost;
10 };
11 class Solution {
12 public:
13     int getCost(vector<int> point1, vector<int> point2) {
14         return abs(point1[0] - point2[0]) + abs(point1[1] - point2[1]);
15     }
16     int minCostConnectPoints(vector<vector<int>>& points) {
17         if (points.size() == 0) {
18             return 0;
19         }
20         int size = points.size();
21         priority_queue<Edge, vector<Edge>, cmp> pq; // 最小堆
22         vector<bool> visited(size, false);
23         int res = 0; // 总费用
24         int cnt = size - 1; // 边数
25         // 以0号顶点为起始点将0号点与其他点形成的边入队
26         for (int i = 1; i < size; i++) {
27             int cost = getCost(points[0], points[i]);
28             Edge edge(0, i, cost);
29             pq.push(edge);
30         }
31         visited[0] = true; // 标记0号点已访问
32         while (!pq.empty() && cnt != 0) {
33             auto edge = pq.top();
34             pq.pop();
35             if (visited[edge.point2]) { // 已访问的点形成的边不选取
36                 continue;
37             }
38             res += edge.cost;
39             visited[edge.point2] = true;
40             for (int i = 0; i < size; i++) {
41                 if (!visited[i]) {
42                     int cost = getCost(points[edge.point2], points[i]);
43                     Edge nextEdge(edge.point2, i, cost);
44                     pq.push(nextEdge);
45                 }
46             }
47             cnt--;
48         }
49         return res;
50     }
51     struct cmp {
52         bool operator() (Edge &a, Edge &b ) {
53             return a.cost > b.cost;//最小堆
54         }
55     };
56 };
复制代码

 

posted @   跳动的休止符  阅读(35)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
点击右上角即可分享
微信分享提示