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 };
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了