力扣:1584.连接所有点的最小费用【kruskal】【结构体和stl速度】
1、 问题描述
给你一个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) 两两不同。
2、 kruskal算法
最小生成树,以最少的边,最小权重的边连接所有顶点生成的树。(树不能存在环路)
krauskal每次选择最短的边连接两个顶点,逐步连接完所有顶点。
并查集思想,在满足构造最小生成树的要求之上,每次选择权重最小的边连接顶点。
3、 问题解答
首先引入并查集的数据结构:
vector<int>parent;//记录每个并查集的爹
vector<int> size;//记录每个并查集的元素个数
void uf(int n){//初始化
this->parent.resize(n);
this->size.resize(n, 1);
for(int i = 0; i < n; i++){
parent[i] = i;//初始状态每个人的爹是它自己
}
}
int find(int x){//寻找x的爹,并进行压缩树的深度
while(x != parent[x]){
parent[x] = parent[parent[x]];
x = parent[x];
}
return x;
}
void merge(int x, int y){//合并两个并查集
int rootx = find(x);
int rooty = find(y);
if(rootx == rooty)return;
//将大小较小的并查集合并到大的并查集的下边,以保证并查集深度较小
if(size[rootx] < size[rooty]){
parent[rootx] = rooty;
size[rooty] += size[rootx];
}else{
parent[rooty] = rootx;
size[rootx] += size[rooty];
}
}
-
引入并查集(上边)
-
构造边Edge结构体记录每个边的起点,终点,权重
struct Edge{ int i; int j; int len; Edge(int i,int j, int len): i(i), j(j), len(len){} };
-
对边进行排序,从小到大
-
对排序后的边进行遍历,每次选择最小的边进行合并,如果这个边合并之后会导致环的出现,则跳过
-
计算总的边数,当边数与总的顶点数目相差1的时候跳出循环
-
返回结果
完整代码如下
class Solution {
public:
vector<int>parent;
vector<int> size;
void uf(int n){
this->parent.resize(n);
this->size.resize(n, 1);
for(int i = 0; i < n; i++){
parent[i] = i;
}
}
int find(int x){
while(x != parent[x]){
parent[x] = parent[parent[x]];
x = parent[x];
}
return x;
}
void merge(int x, int y){
int rootx = find(x);
int rooty = find(y);
if(rootx == rooty)return;
if(size[rootx] < size[rooty]){
parent[rootx] = rooty;
size[rooty] += size[rootx];
}else{
parent[rooty] = rootx;
size[rootx] += size[rooty];
}
}
struct Edge{
int i;
int j;
int len;
Edge(int i,int j, int len): i(i), j(j), len(len){}
};
static bool cmp(Edge a,Edge b){
return a.len < b.len;
}
int minCostConnectPoints(vector<vector<int>>& points) {
int n = points.size();
uf(n);
vector<Edge> edges;
for(int i = 0; i < n ;i++){
for(int j = i+1; j < n; j++){
int x1 = points[i][0], y1 = points[i][1];
int x2 = points[j][0], y2 = points[j][1];
int cost = abs(x1 - x2) + abs(y1 - y2);
edges.emplace_back(i,j,cost);
}
}
sort(edges.begin(), edges.end(), cmp);
int sum = 0;
int count = 0;
for(auto edge : edges){
int x = edge.i;
int y = edge.j;
if(find(x) == find(y))continue;
if(find(x) != find(y)){
merge(x,y);
count++;
sum += edge.len;
if(count == n-1)break;
}
}
return sum;
}
};
4、 stl速度慢过不去
class Solution {
public:
vector<int>parent;
vector<int> size;
void uf(int n){
this->parent.resize(n);
this->size.resize(n);
for(int i = 0; i < n; i++){
parent[i] = i;
size[i] = 1;
}
}
int find(int x){
while(x != parent[x]){
parent[x] = parent[parent[x]];
x = parent[x];
}
return x;
}
void merge(int x, int y){
int rootx = find(x);
int rooty = find(y);
if(rootx == rooty)return;
if(size[rootx] < size[rooty]){
parent[rootx] = rooty;
size[rooty] += size[rootx];
}else{
parent[rooty] = rootx;
size[rootx] += size[rooty];
}
}
static bool cmp(vector<int> a,vector<int> b){
return a[2]<b[2];
}
int minCostConnectPoints(vector<vector<int>>& points) {
int n = points.size();
uf(n);
vector<vector<int>> edges;
for(int i = 0; i < n ;i++){
for(int j = i+1; j < n; j++){
int x1 = points[i][0], y1 = points[i][1];
int x2 = points[j][0], y2 = points[j][1];
int cost = abs(x1 - x2) + abs(y1 - y2);
edges.push_back({i, j, cost});
}
}
sort(edges.begin(), edges.end(), cmp);
int sum = 0;
int count = 0;
for(auto edge : edges){
if(count == n-1)break;
int x = edge[0];
int y = edge[1];
if(find(x) == find(y))continue;
if(find(x) != find(y)){
merge(x,y);
count++;
sum += edge[2];
}
}
return sum;
}
};
上边这个代码用二维vector储存边,vector[i][0]
储存起点,vector[i][1]
储存终点,vector[i][2]
储存权重。
与第一种同样的处理方法,通过不了全部力扣样例。