最小生成树

最小,生成 · 浏览次数 : 9

小编点评

**算法流程:** 1. 初始化所有距离为正无穷,保存已经选的点集合。 2. 遍历所有点,找到距离最小的点并加入集合。 3. 对于每个点,更新其距离所有点距离的最小值。 4. 如果当前点距离所有点距离已达到最大值,则无法加入集合,返回不符合条件。 5. 遍历所有连接当前点的边,如果这条边与当前选出的边不在同一个集合中,则加入集合并更新其距离。 6. 返回最小生成树的边数。 **Kruskal算法的流程:** 1. 将所有边按照权值从小到大排序。 2. 遍历所有边,如果这条边与当前选出的所有边不在同一个集合中,则加入集合并更新其距离。 3. 选择具有最小距离的边,直到选出了N-1条边。 4. 如果当前边数不等于N-1,则无法构造最小生成树,返回不符合条件。 5. 返回最小生成树的边数。 **时间复杂度:** * 最小生成树算法:O(n * log(m)) * Kruskal算法:O(n * log(m))

正文

什么是最小生成树

给定一个图,在图中选择N - 1条边(N代表图的点数)把图的所有节点都连起来,且边的权值最小,则这N - 1条边就是原图的最小生成树。

如何求最小生成树

求最小生成树有两种算法:

  1. prim

  2. kruskal

prim算法

其实本质上和dijstra算法很像。

适用于稠密图。

题目:

image

算法流程:

  1. 将所有点到已经选的点的集合的距离设为正无穷。

  2. 每次找到dis最小的点,加入到集合中。

  3. 使用该点的距离更新所有点到集合距离(注意:我们之前已经确定过的点不需要再被改变dis,所以说我们要特殊确定一下)。

代码:

#include <bits/stdc++.h>
#define N 510
using namespace std;
int n, m;
int g[N][N];
int dis[N];
bool st[N];
int prim() {
    memset(dis, 0x3f, sizeof dis);
    dis[1] = 0;
    int ans = 0;
    for (int i = 1; i <= n; ++i) {
        int minid = -1; //	dis最小的点
        for (int j = 1; j <= n; ++j)
            if (!st[j] && (minid == -1 || dis[j] < dis[minid]))
                minid = j;
        if (dis[minid] == 0x3f3f3f3f)
            return 0x3f3f3f3f; //	不符合条件
        ans += dis[minid];
        st[minid] = true;
        for (int j = 1; j <= n; ++j)
            dis[j] = min(dis[j], g[minid][j]); //	更新距离
    }
    return ans;
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    memset(g, 0x3f, sizeof g);
    cin >> n >> m;
    while (m--) {
        int a, b, c;
        cin >> a >> b >> c;
        g[a][b] = g[b][a] = min(g[a][b], c);
    }
    int t = prim();
    if (t == 0x3f3f3f3f)
        puts("impossible");
    else
        cout << t << '\n';
    return 0;
}

kruskal算法

适用于稀疏图。

题目:

image

前置知识:并查集

如果不会并查集,可以看我的另外一篇博客:【数据结构】并查集

算法流程:

  1. 将所有边按照权值从小到大排序。
  2. 如果这条边与之前选出来的所有边不会形成环(使用并查集判断),那么就使用这条边,否则舍去这条边。
  3. 直到选出了N-1条边,算法结束。

代码:

#include <bits/stdc++.h>
#define N 100010
using namespace std;
int p[N]; //  并查集
struct Egde {
    int a, b, c;
    bool operator<(const Egde& t) const {
        return c < t.c;
    } //  按边权从小到大排序
} edges[N * 2];
int n, m;
int cnt, ans;
int find(int x) {
    if (p[x] != x)
        p[x] = find(p[x]);
    return p[x];
}
void kruskal() {
    for (int i = 1; i <= m; ++i) {
        int a = find(edges[i].a), b = find(edges[i].b), c = edges[i].c;
        if (a != b) {
            ans += c;
            cnt++;
            p[a] = b;
        }
    }
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    cin >> n >> m;
    for (int i = 1; i <= n; ++i)
        p[i] = i;
    for (int i = 1; i <= m; ++i) {
        int a, b, c;
        cin >> a >> b >> c;
        edges[i] = {a, b, c};
    }
    sort(edges + 1, edges + m + 1);
    kruskal();
    if (cnt < n - 1) { //  选出的边数不是N-1条,不符合条件
        puts("impossible");
        return 0;
    }
    cout << ans << '\n';
    return 0;
}

与最小生成树相似的内容:

VUE系列之性能优化--懒加载

一、懒加载的基本概念 懒加载是一种按需加载技术,即在用户需要时才加载相应的资源,而不是在页面初始加载时一次性加载所有资源。这样可以减少页面初始加载的资源量,提高页面加载速度和用户体验。 二、Vue 中的懒加载 在 Vue.js 中,懒加载主要用于路由组件的按需加载。Vue Router 提供了非常便

深入理解 Vue 3 组件通信

在 Vue 3 中,组件通信是一个关键的概念,它允许我们在组件之间传递数据和事件。本文将介绍几种常见的 Vue 3 组件通信方法,包括 props、emits、provide 和 inject、事件总线以及 Vuex 状态管理。 1. 使用 props 和 emits 进行父子组件通信 props

前端开发中的二分查找算法

在前端开发中,处理和搜索大量数据时,效率是一个关键因素。二分查找算法是一种高效的查找算法,适用于在有序数组中快速找到目标值。本文将详细介绍二分查找算法的基本原理、实现方法及其在前端开发中的应用。 什么是二分查找? 二分查找(Binary Search)是一种在有序数组中查找目标值的算法。它通过不断将

前端回流与重绘:概念及触发条件

在前端开发中,性能优化是一个永恒的话题。回流(Reflow)与重绘(Repaint)是两个重要的概念,它们直接影响着页面的渲染性能和用户体验。本文将详细介绍回流与重绘的概念、触发条件及其优化方法。 一、回流(Reflow)(重排) 1.1 概念 回流,又称重排(Reflow),是指当DOM的变化引起

前端开发-- Webpack 代码分割和懒加载技术

在现代前端开发中,优化应用性能是一个至关重要的任务。Webpack 作为一个强大的打包工具,为我们提供了代码分割和懒加载的功能,可以显著提升应用的加载速度和用户体验。本文将深入解析 Webpack 的代码分割和懒加载技术,帮助开发者更好地理解和应用这些技术。 什么是代码分割? 代码分割(Code S

探索贪心算法:解决优化问题的高效策略

贪心算法是一种在每一步选择中都采取当前最佳选择的算法,以期在整体上达到最优解。它广泛应用于各种优化问题,如最短路径、最小生成树、活动选择等。本文将介绍贪心算法的基本概念、特点、应用场景及其局限性。 贪心算法的基本概念 贪心算法的核心思想是局部最优策略,即在每一步选择中都选择当前看起来最优的选项,希望

最小生成树

## 什么是最小生成树 给定一个图,在图中选择N - 1条边(N代表图的点数)把图的所有节点都连起来,且边的权值最小,则这N - 1条边就是原图的最小生成树。 ## 如何求最小生成树 求最小生成树有两种算法: 1. prim 2. kruskal ## prim算法 其实本质上和dijstra算法很

学习笔记——斯坦纳树

斯坦纳树 斯坦纳树问题是组合优化问题,与最小生成树相似,是最短网络的一种。最小生成树是在给定的点集和边中寻求最短网络使所有点连通。而最小斯坦纳树允许在给定点外增加额外的点,使生成的最短网络开销最小。 百度百科 在图论里,一般用于解决形如: 给定一个连通图 \(G\),给定 \(k\) 个关键点,选取

算法学习笔记(30):Kruskal 重构树

Kruskal 重构树 这是一种用于处理与最大/最小边权相关的一个数据结构。 其与 kruskal 做最小生成树的过程是类似的,我们考虑其过程: 按边权排序,利用并查集维护连通性,进行合并。 如果我们在合并时,新建一个节点,其权值为当前处理的边的权值,并将合并的两个节点都连向新建的节点,那么就可以得

Solution -「LOJ #3310」丁香之路

首先有两个前置技巧:1) 两点间的最短距离就是直接连接两点的边的长度;2) 遍历一个子图的最小花费是最小生成树的边权之和乘二。原问题让我们找出一条最短且必经过钦定边的 \(( s, i )\) 路径,那么我们先将 \(\lang s , i \rang\) 连上,问题就变成了找出一条最短且必经过钦定