问题描述
给你一个
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
-10^6 <= xi, yi <= 10^6
- 所有点
(xi, yi)
两两不同。
问题分析:
记录一道经典Kruskal算法,思路很简单:首先生成一个边权图,根据已知节点计算权值,对对应权值进行排序。每次挑选最小权重的边进行连接,同时判断会不会形成环。说到这里其实已经很清晰了,并查集就是为这个问题服务的。具体见代码。
代码如下:
// 经典并查集模板
class UF {vector<int> parent;public:UF(int n) {for (int i = 0; i < n; ++i) {parent.push_back(i);}}int find(int x) {if (x != parent[x]) {parent[x] = find(parent[x]);}return parent[x];}void _union(int x, int y) {int rootX = find(x);int rootY = find(y);if (rootX != rootY) {parent[rootX] = rootY;}}bool isConnected(int x, int y) { return find(x) == find(y); }
};
class Solution {
public:int minCostConnectPoints(vector<vector<int>>& points) {int n = points.size();vector<vector<int>> edges;// 建立边权图for (int i = 0; i < n; ++i) {for (int j = i + 1; j < n; ++j) {int xi = points[i][0], yi = points[i][1];int xj = points[j][0], yj = points[j][1];edges.push_back({i, j, abs(xi - xj) + abs(yi - yj)});}}// 根据权重进行排序sort(edges.begin(), edges.end(),[](const auto& a, const auto& b) { return a[2] < b[2]; });// 返回最终结果int mst = 0;UF uf(n);for (int i = 0; i < edges.size(); ++i) {int u = edges[i][0];int v = edges[i][1];int w = edges[i][2];// 如果uv之前已经连通,再连接会成环,所以跳过这次连接if (uf.isConnected(u, v)) {continue;}mst += w;// 连接uvuf._union(u, v);}return mst;}
};