目录
一、题目描述
给你一个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) 两两不同。
二、解题思路
这道题是最下生成树的典型题型,重点记录下求最小生成树的两种方法。
以下图文转自力扣题解区Philos大佬的题解。
kreskal(克鲁斯卡尔)方法:
此算法可以称为“加边法”,初始最小生成树边数为0,每迭代一次就选择一条满足条件的最小代价边,加入到最小生成树的边集合里。
- 把图中的所有边按代价从小到大排序;
- 把图中的n个顶点看成独立的n棵树组成的森林;
- 按权值从小到大选择边,所选的边连接的两个顶点 ,, 两个顶点应属于两颗不同的树(一棵树上的两条个顶点相连的话就形成环了),则成为最小生成树的一条边,并将这两颗树合并作为一颗树。
- 重复(3),直到所有顶点都在一颗树内或者有n-1条边为止。
适合稀疏图;
prim(普利姆)算法:
此算法可以称为“加点法”,每次迭代选择代价最小的边对应的点,加入到最小生成树中。算法从某一个顶点s开始,逐渐长大覆盖整个连通网的所有顶点。
- 图的所有顶点集合为 ;初始令集合 ,;
- 在两个集合 , 能够组成的边中,选择一条代价最小的边 ,加入到最小生成树中,并把加入到集合中。
- 重复上述步骤,直到最小生成树有 n-1 条边或者 n 个顶点为止。
适合稠密图;
三、代码实现
#include <bits/stdc++.h>
using namespace std;
struct edge {
int a, b, weight;
//定义比较操作
bool operator<(const edge& e) const {
return weight < e.weight;
}
};
vector<int> father;
int numOfEdges = 0;
void init(int n) {
for (int i = 0; i < n; i++) {
father.push_back(i);
}
}
int findFather(int x) {
if (x == father[x]) {
return x;
}
//这里不用路径压缩
return findFather(father[x]);
}
void Union(int a, int b) {
int Fa = findFather(a);
int Fb = findFather(b);
if (Fa != Fb) {
father[Fa] = Fb;
}
}
int minCostConnectPoints(int n, vector<edge>& Edges) {
numOfEdges = n;
int res = 0;
init(n);
sort(Edges.begin(), Edges.end());
for (int i = 0; i < Edges.size(); i++) {
int fa = findFather(Edges[i].a);
int fb = findFather(Edges[i].b);
if (fa != fb) {
Union(fa, fb);
res += Edges[i].weight;
//添加一条边要改变边的计数
numOfEdges--;
}
//如果加了n-1条边就结束
if (numOfEdges == 1) {
return res;
}
}
return res;
}
int minCostConnectPoints(vector<vector<int>>& points) {
int length = points.size();
vector<edge> Edges;
for (int i = 0; i < length; i++) {
for (int j = i + 1; j < length; j++) {
//处理边的连接矩阵
Edges.push_back({ i, j, abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1]) });
}
}
return minCostConnectPoints(length, Edges);
}
int main() {
vector<vector<int>> points = { {0,0},{2,2},{3,10},{5,2},{7,0} };
cout << minCostConnectPoints(points) << " ";
return 0;
}