【算法·命运-36】prim算法

Prim 算法(Prim's Algorithm)

Prim 算法 是一种 贪心算法,用于计算 加权无向图最小生成树(MST)。最小生成树是一个包含图中所有节点的树,且其边的权重和最小。

Prim 算法的基本思想:
  • 从图中的一个节点开始,逐步扩展最小生成树(MST),每次选择与已经生成树相连的、权重最小的边。
  • 算法不断地将图中的未访问节点添加到树中,直到所有节点都包含在生成树中为止。
  • 在每一步,算法都会选择与已经包含在生成树中的节点集合相连接的、权值最小的边。
算法步骤:
  1. 初始化:选择一个起始节点,将其加入到生成树中。此时,生成树包含的节点数为 1。
  2. 维护一个优先队列(最小堆):优先队列用于存储从当前生成树中已加入的节点到未加入节点的边,并根据边的权重进行排序,始终取出最小权重的边。
  3. 逐步扩展生成树
    • 从优先队列中取出一条权重最小的边(假设连接的两个节点分别是 uv),将节点 v 加入生成树。
    • 将从新加入的节点 v 出发且未被访问过的边加入优先队列。
  4. 重复以上过程,直到所有节点都被加入生成树中。
Prim 算法的时间复杂度:
  • 使用邻接矩阵表示图时,时间复杂度为 O(V²),其中 V 是图中的节点数。
  • 使用邻接表和 最小堆(优先队列)时,时间复杂度为 O(E log V),其中 E 是图中的边数。
算法特点:
  • 贪心策略:每一步都选择当前最小的边,确保能够得到全局最优解。
  • 适用于稠密图:当图的边数较多时,Prim 算法通常比 Kruskal 算法更有效。
  • 不需要对图进行排序:与 Kruskal 算法不同,Prim 算法不需要对所有边进行排序,直接通过优先队列动态选择边。
Prim 算法的实现(Python):

我们将图表示为邻接表,并使用 Python 的 heapq 库实现优先队列。

import heapq

def prim(graph, V):
    # 初始化数据
    mst_cost = 0  # 最小生成树的总权重
    visited = [False] * V  # 标记哪些节点已经在生成树中
    min_heap = [(0, 0)]  # 最小堆,初始化时从节点 0 开始,权重为 0
    edges_in_mst = []  # 存储最小生成树的边
    
    while min_heap:
        weight, u = heapq.heappop(min_heap)  # 获取最小权重的边
        if visited[u]:  # 如果节点已经在生成树中,则跳过
            continue
        visited[u] = True  # 将节点 u 加入生成树
        mst_cost += weight  # 累加边的权重
        for v, w in graph[u]:  # 遍历与 u 相连的所有邻接节点
            if not visited[v]:  # 如果邻接节点 v 不在生成树中
                heapq.heappush(min_heap, (w, v))  # 将 v 加入最小堆
                
        edges_in_mst.append((u, v, weight))  # 记录生成树中的边
        
    return mst_cost, edges_in_mst

# 示例图:邻接表表示,graph[u] = [(v1, w1), (v2, w2), ...]
graph = {
    0: [(1, 1), (2, 4), (3, 3)],
    1: [(0, 1), (2, 2), (3, 5)],
    2: [(0, 4), (1, 2), (3, 1)],
    3: [(0, 3), (1, 5), (2, 1)]
}

V = 4  # 节点数
mst_cost, edges_in_mst = prim(graph, V)
print("Minimum cost of the MST:", mst_cost)
print("Edges in the MST:", edges_in_mst)
示例解释:
  1. 图的表示:使用邻接表表示图,其中 graph[u] = [(v1, w1), (v2, w2), ...] 表示从节点 u 出发的边及其权重。例如,(1, 1) 表示从节点 0 到节点 1 的边的权重为 1
  2. 最小堆:优先队列(最小堆)用于每次选择权重最小的边,并确保优先选择最小的边来扩展生成树。
  3. 最终输出
    • mst_cost:最小生成树的总权重。
    • edges_in_mst:最小生成树中的边。
时间复杂度:
  • 时间复杂度:O(E log V),使用最小堆时,每次操作(插入和删除)都是 O(log V),对于每条边,最多会进行一次堆操作,因此总的复杂度为 O(E log V)。
Prim 算法与 Kruskal 算法的比较:
  • Kruskal 算法:是基于边的排序来逐步选择最小权重的边,适用于稀疏图,使用 并查集 来检测环。
  • Prim 算法:是基于节点的扩展,适用于稠密图,使用 优先队列 来选择最小权重的边。
适用场景:
  • Prim 算法特别适用于 稠密图(图中边数较多的情况),因为它不需要对所有边进行排序,且优先队列能够动态地选择边。
  • 对于 稀疏图(图中边数较少),Kruskal 算法 可能会更有效。

总结:

  • Prim 算法 是一个经典的 贪心算法,用于求解图的 最小生成树
  • 时间复杂度:O(E log V)(使用优先队列时),O(V²)(使用邻接矩阵时)。
  • 优点:适合稠密图,能够动态地扩展生成树,计算最小生成树的效率较高。
  • 缺点:对于稀疏图,可能不如 Kruskal 算法高效。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值