图论(三)之最小生成树(kurskal/Prim)

Minimum Spanning Tree

两大算法: KruskalPrim

树的含义:

  • 结构中不能形成环

  • 必须连接图结构中的全部顶带,任意两个顶点都是互通的

不同的生成树有不同的权值和,而最小生成树即为最小的那个树

如何构造最小生成树

**目标:**权值和达到最小值

每一步优先选择权值最小的边

Kruskal:直接选择权值最小的边

Prim:从顶点出发,间接选择与顶点相连权值最小的边

Kruskal Algorithm
  1. 将图中所有边取出,放入一个列表,并按照边取值按从小到大的顺序重新排列

  2. 回填,从列表中按照次序每次取出一条边,回填到图中

  3. 每次回填到图中时,进行判断图中是否形成环

    1. 若没有出现环,则选中此条边
    2. 若出现环,那么丢弃此边,选择下条边进行遍历判断
  4. 直到已经选了n - 1条边,构建完成


Prim Algorithm

问题引入

有8个城市,他们的距离各不相同,假如在他们之间铺设铁路,要怎么才能使得费用最小呢

  • 首先选择一个起始点,选择相连的权值最小的边
  • 把选择的城市加入选定城市集合中
  • 接着观察所有选定城市的边,再次选择权值最小的边
  • 直到所有城市都被加入进选定城市集合中,算法结束
相关例题
Prim Algorithm

https://www.acwing.com/problem/content/860/

题目如下:

完整代码
cpp 复制代码
#include <iostream>
#include <cstring>
using namespace std;
const int N = 510;
int g[N][N];    //存储图,g[i][j],从i到j的距离
int dist[N];    //存储某个节点到选定集合的最短距离
bool st[N]; //判断是否在选定集合
int n, m;

void prim() {
    memset(dist, 0x3f3f3f3f, sizeof dist);
    dist[1] = 0;//从1号节点开始生成
    int res = 0;    //权重和
    for(int i = 0; i < n; i++) {    //每次循环选出一个点加入到选定集合中
        int t = -1;
        for(int j = 1; j <= n; j++) {   //对每个节点进行判断
            if(!st[j] && (t == -1 || dist[j] < dist[t]))
                t = j;  //找到距离最小的t
        }
        
        if(dist[t] == 0x3f3f3f3f) {   //若最小的为无穷,那么这块肯定短路,走不通
            printf("impossible");   //这里因为边权可能为负数
            return;
        }
        //else 
        st[t] = true;   //合理则选定t
        res += dist[t]; //更新答案
        for(int j = 1; j <= n; j++) {   //与最短点t相连的边
            if(!st[j]) {//从 t 到节点 i 的距离小于原来距离,则更新。
                dist[j] = min(dist[j], g[t][j]);  //更新dist[j]
            }
        }
    }
    cout << res;
}

int main() {
    memset(g, 0x3f3f3f3f, sizeof g);
    cin >> n >> m;
    while(m --) {
        int a, b, w;
        scanf("%d%d%d", &a, &b, &w);
        g[a][b] = g[b][a] = min(w, g[a][b]);    //存储权重,去重边
    }
    prim();
    
    return 0;
}
Kruskal Algorithm

https://www.acwing.com/problem/content/861/

题目如下:

思路分析
完整代码
cpp 复制代码
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 200010, INF = 0x3f3f3f3f;
int n, m;
int p[N];
struct Edge{
    int a, b, w;
    bool operator< (const Edge &W)const {
        return w < W.w;
    }
}edges[N];

int find(int x) {   //并查集的操作
    if(p[x] != x)   p[x] = find(p[x]);
    return p[x];
}

int kruskal() {
    sort(edges, edges + m); //先进行排序,然后进行查找
    for(int i = 1; i <= n; i++) p[i] = i;   //并查集初始化
    int res = 0, cnt = 0;
    for(int i = 0; i < m; i++) {
        int a = edges[i].a, b = edges[i].b, w = edges[i].w;
        a = find(a), b = find(b);
        if(a != b) {    //若不连通,那么连通,并加入集合
            p[a] = b;
            res += w;
            cnt++;
        }
    }
    if(cnt < n - 1) res = INF;
    return res;
}

int main() {
    scanf("%d%d", &n, &m);
    for(int i = 0; i < m; i++) {
        int a, b, w;
        scanf("%d%d%d", &a, &b, &w);
        edges[i] = {a, b, w};
    }
    int t = kruskal();
    if(t == INF)  puts("impossible");
    else printf("%d\n", t);
    
    return 0;
}
相关推荐
松涛和鸣11 小时前
DAY32 Linux Thread Programming
linux·运维·数据库·算法·list
LYFlied11 小时前
【每日算法】LeetCode 234. 回文链表详解
算法·leetcode·链表
NeDon11 小时前
[OJ]数据结构:移除链表元素
c语言·数据结构·算法·链表
刃神太酷啦11 小时前
C++ list 容器全解析:从构造到模拟实现的深度探索----《Hello C++ Wrold!》(16)--(C/C++)
java·c语言·c++·qt·算法·leetcode·list
承渊政道11 小时前
一文彻底搞清楚链表算法实战大揭秘和双向链表实现
c语言·数据结构·算法·leetcode·链表·visual studio
sali-tec12 小时前
C# 基于halcon的视觉工作流-章69 深度学习-异常值检测
开发语言·图像处理·算法·计算机视觉·c#
努力写代码的熊大12 小时前
手撕AVL树:从理论到实践,掌握插入操作的完美平衡
算法
wbs_scy12 小时前
C++:二叉搜索树(BST)完全指南(从概念原理、核心操作到底层实现)
数据结构·算法
东华万里12 小时前
Release 版本禁用 assert:NDEBUG 的底层逻辑与效率优化
java·jvm·算法