图论(三)之最小生成树(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;
}
相关推荐
jiao_mrswang44 分钟前
leetcode-18-四数之和
算法·leetcode·职场和发展
qystca1 小时前
洛谷 B3637 最长上升子序列 C语言 记忆化搜索->‘正序‘dp
c语言·开发语言·算法
薯条不要番茄酱1 小时前
数据结构-8.Java. 七大排序算法(中篇)
java·开发语言·数据结构·后端·算法·排序算法·intellij-idea
今天吃饺子1 小时前
2024年SCI一区最新改进优化算法——四参数自适应生长优化器,MATLAB代码免费获取...
开发语言·算法·matlab
是阿建吖!1 小时前
【优选算法】二分查找
c++·算法
王燕龙(大卫)1 小时前
leetcode 数组中第k个最大元素
算法·leetcode
不去幼儿园2 小时前
【MARL】深入理解多智能体近端策略优化(MAPPO)算法与调参
人工智能·python·算法·机器学习·强化学习
Mr_Xuhhh2 小时前
重生之我在学环境变量
linux·运维·服务器·前端·chrome·算法
盼海3 小时前
排序算法(五)--归并排序
数据结构·算法·排序算法
网易独家音乐人Mike Zhou6 小时前
【卡尔曼滤波】数据预测Prediction观测器的理论推导及应用 C语言、Python实现(Kalman Filter)
c语言·python·单片机·物联网·算法·嵌入式·iot