当前位置: 首页 > news >正文

⭐算法OJ⭐连接所有点的最小费用【最小生成树】(C++实现)Min Cost to Connect All Points

文章目录

  • 问题描述
  • 解题思路
    • 方法1:Kruskal算法(推荐)
      • 代码实现(Kruskal + Union-Find)
      • 复杂度分析
    • 方法2:Prim算法
      • 代码实现(Prim算法)
      • 复杂度分析

1584. Min Cost to Connect All Points
You are given an array points representing integer coordinates of some points on a 2D-plane, where points[i] = [xi, yi].

The cost of connecting two points [xi, yi] and [xj, yj] is the manhattan distance between them: |xi - xj| + |yi - yj|, where |val| denotes the absolute value of val.

Return the minimum cost to make all points connected. All points are connected if there is exactly one simple path between any two points.

问题描述

给定一组二维平面上的点,其中 points[i] = [xi, yi]。连接两点 [xi, yi][xj, yj] 的费用是它们之间的曼哈顿距离:|xi - xj| + |yi - yj|。返回连接所有点所需的最小总费用。所有点都应该被连接,并且任意两点之间有且只有一条路径。

Example 1:
在这里插入图片描述

Input: points = [[0,0],[2,2],[3,10],[5,2],[7,0]]
Output: 20

Explanation:

We can connect the points as shown above to get the minimum cost of 20.
Notice that there is a unique path between every pair of points.
在这里插入图片描述

Example 2:

Input: points = [[3,12],[-2,5],[-4,1]]
Output: 18

解题思路

这是一个典型的 最小生成树(MST) 问题,可以使用 Kruskal算法 或 Prim算法 解决。

方法1:Kruskal算法(推荐)

  • 计算所有边:生成所有可能的点对,并计算它们的曼哈顿距离。
  • 按权重排序边:从小到大排序所有边。
  • 使用并查集(Union-Find):
    • 初始化每个点为一个独立的集合。
    • 遍历排序后的边,如果两个点不在同一集合,就合并它们,并累加费用。
    • 直到所有点连通(即边的数量 = n-1,其中 n 是点的数量)。

代码实现(Kruskal + Union-Find)

#include <vector>
#include <algorithm>
using namespace std;class UnionFind {
private:vector<int> parent;vector<int> rank;
public:UnionFind(int n) {parent.resize(n);rank.resize(n, 0);for (int i = 0; i < n; i++) {parent[i] = i;}}int find(int u) {if (parent[u] != u) {parent[u] = find(parent[u]); // Path compression}return parent[u];}bool unionSets(int u, int v) {int rootU = find(u);int rootV = find(v);if (rootU == rootV) return false; // Already connectedif (rank[rootU] > rank[rootV]) {parent[rootV] = rootU;} else if (rank[rootU] < rank[rootV]) {parent[rootU] = rootV;} else {parent[rootV] = rootU;rank[rootU]++;}return true;}
};class Solution {
public:int minCostConnectPoints(vector<vector<int>>& points) {int n = points.size();vector<vector<int>> edges; // {cost, u, v}// Generate all possible edgesfor (int i = 0; i < n; i++) {for (int j = i + 1; j < n; j++) {int cost = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1]);edges.push_back({cost, i, j});}}// Sort edges by costsort(edges.begin(), edges.end());UnionFind uf(n);int res = 0;int edgesUsed = 0;for (auto& edge : edges) {int cost = edge[0], u = edge[1], v = edge[2];if (uf.unionSets(u, v)) {res += cost;edgesUsed++;if (edgesUsed == n - 1) break;}}return res;}
};

复杂度分析

  • 时间复杂度: O ( n ² l o g n ) O(n^² log n) O(n²logn)(排序边)。
  • 空间复杂度: O ( n ² ) O(n^²) O(n²)(存储所有边)。

方法2:Prim算法

  • 初始化优先队列(最小堆):从任意一个点开始,将其所有邻边加入堆。
  • 逐步扩展MST:
    • 每次取出权重最小的边,如果该边连接的点未被访问,则加入MST,并累加费用。
    • 将该点的所有邻边加入堆。
  • 直到所有点都被访问。

代码实现(Prim算法)

#include <vector>
#include <queue>
#include <climits>
using namespace std;class Solution {
public:int minCostConnectPoints(vector<vector<int>>& points) {int n = points.size();vector<bool> visited(n, false);priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> minHeap;// Start with node 0minHeap.push({0, 0});int res = 0;int edgesUsed = 0;while (edgesUsed < n) {auto [cost, u] = minHeap.top();minHeap.pop();if (visited[u]) continue;visited[u] = true;res += cost;edgesUsed++;// Add all edges from u to unvisited nodesfor (int v = 0; v < n; v++) {if (!visited[v]) {int newCost = abs(points[u][0] - points[v][0]) + abs(points[u][1] - points[v][1]);minHeap.push({newCost, v});}}}return res;}
};

复杂度分析

  • 时间复杂度: O ( n ² l o g n ) O(n^² log n) O(n²logn)(优先队列操作)。
  • 空间复杂度: O ( n ) O(n) O(n)(存储 visited 和优先队列)。

http://www.mrgr.cn/news/95916.html

相关文章:

  • P4147 玉蟾宫
  • MySQL数据库中常用的命令
  • 【NLP 43、大模型技术发展】
  • 【Python LeetCode Patterns】刷力扣,15 个学习模式总结
  • 常用序列的离散时间傅里叶变换(DTFT)
  • Win32 / C++ ini配置文件解析类(支持简易加解密)
  • 【算法】动态规划:回文子串问题、两个数组的dp
  • 3.24[Q]Linux
  • PCL 点云多平面探测
  • 新一代可编程网关应用举例
  • Python Sanic面试题及参考答案
  • P1182 数列分段 Section II
  • 一次由特殊字符引发的Minio签名问题排查
  • 保姆级教程搭建企业级智能体+私有知识库,Dify+ollama,Linux版
  • 基于Python的自然语言处理系列(60):使用 LangChain 构建 Multi-Vector Retriever 进行文档检索
  • ESP-SPARKBOT AI 智能机器人:v1.2 全流程复刻指南
  • 论坛系统测试报告
  • 给Web开发者的HarmonyOS指南02-布局样式
  • Linux 挂载磁盘操作指南
  • 代理记账的第三个十年