leetCode1584:连接所有点的最小费用

目录

一、题目描述

二、解题思路

三、代码实现


一、题目描述

给你一个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,每迭代一次就选择一条满足条件的最小代价边,加入到最小生成树的边集合里。

  1. 把图中的所有边按代价从小到大排序;
  2. 把图中的n个顶点看成独立的n棵树组成的森林;
  3. 按权值从小到大选择边,所选的边连接的两个顶点 u_{i},v_{i}, 两个顶点应属于两颗不同的树(一棵树上的两条个顶点相连的话就形成环了),则成为最小生成树的一条边,并将这两颗树合并作为一颗树。
  4. 重复(3),直到所有顶点都在一颗树内或者有n-1条边为止。

适合稀疏图;

prim(普利姆)算法:

此算法可以称为“加点法”,每次迭代选择代价最小的边对应的点,加入到最小生成树中。算法从某一个顶点s开始,逐渐长大覆盖整个连通网的所有顶点。

  1. 图的所有顶点集合为 V;初始令集合 u= s,v = V -u;
  2. 在两个集合 u,v 能够组成的边中,选择一条代价最小的边 (u_{0},v_{0}),加入到最小生成树中,并把v_{0}加入到集合u中。
  3. 重复上述步骤,直到最小生成树有 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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值