Prim算法

1. 算法概述

Prim算法是一种用于求解加权无向连通图的最小生成树(MST)的贪心算法。

核心思想

  • 从任意顶点开始,逐步扩展生成树

  • 每次选择连接树和非树节点的最小权重边

  • 直到所有顶点都包含在生成树中

特点

  • 适用于稠密图

  • 时间复杂度取决于实现方式

  • 总是找到连通图的最小生成树

2. 算法适用条件

✔ 加权无向连通图
✔ 可以处理带权图(权重可以为负)
✖ 不适用于有向图
✖ 图必须连通(否则只能找到连通分量的MST)

3. 算法步骤

初始化阶段

memset(dist, 0x3f, sizeof dist);  // 所有距离初始化为∞
dist[1] = 0;                      // 选择起始点(可以是任意点)
int res = 0;                      // 存储MST的总权重

主循环过程

for(循环n次){
    1. 找到未加入MST的离集合最近的节点t
    2. 如果非首次循环且dist[t]=∞,说明图不连通
    3. 累加该边权重到res
    4. 用t更新其他节点到集合的距离
    5. 将t加入MST集合
}

4. 时间复杂度分析

实现方式时间复杂度适用场景
邻接矩阵+遍历O(V²)稠密图
邻接表+堆优化O(ElogV)稀疏图

5. 代码模板(C++)

邻接矩阵版本(稠密图)

const int N = 510, INF = 0x3f3f3f3f;
int g[N][N], dist[N];
bool st[N];
int n, m;

int prim() {
    memset(dist, 0x3f, sizeof dist);
    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[t] > dist[j]))
                t = j;
                
        if (i && dist[t] == INF) return INF;
        if (i) res += dist[t];
        
        for (int j = 1; j <= n; j++)
            dist[j] = min(dist[j], g[t][j]);
            
        st[t] = true;
    }
    return res;
}

堆优化版本(稀疏图)

typedef pair<int, int> PII;
priority_queue<PII, vector<PII>, greater<PII>> heap;

int prim_heap() {
    memset(dist, 0x3f, sizeof dist);
    dist[1] = 0;
    heap.push({0, 1});
    int res = 0;
    
    while (!heap.empty()) {
        auto t = heap.top();
        heap.pop();
        
        int ver = t.second;
        if (st[ver]) continue;
        st[ver] = true;
        res += t.first;
        
        for (auto edge : adj[ver]) {
            int j = edge.first, w = edge.second;
            if (dist[j] > w) {
                dist[j] = w;
                heap.push({dist[j], j});
            }
        }
    }
    return res;
}

6. 常见问题

Q1:Prim和Kruskal算法如何选择?

  • Prim适合稠密图(邻接矩阵存储)

  • Kruskal适合稀疏图(边排序+并查集)

Q2:如何处理图不连通的情况?

  • 检查算法结束后是否所有顶点都被访问

  • 如果存在未访问顶点,说明图不连通

Q3:为什么Prim算法不能用于有向图?

  • 最小生成树定义基于无向图

  • 有向图的最小树形图需要使用Chu-Liu/Edmonds算法

7. 典型例题

  1. LeetCode 1584. 连接所有点的最小费用

  2. ACWING 858 - Prim算法求最小生成树

8. 优化技巧

  1. 对于稠密图,使用朴素Prim实现更优

  2. 使用堆优化时注意避免重复入队

  3. 输入规模大时使用快速读写

9. 声明

以上笔记仅为学习该算法的学习笔记,如有错误请指出

总结:Prim算法是求解最小生成树问题的经典算法,理解其贪心思想和实现方式对掌握图论算法至关重要。根据图的特点选择合适的实现方式(朴素或堆优化)能显著提高算法效率。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值