求最小生成树(Kruskal算法和Prim算法)

本文介绍了最小生成树的概念及其在无向图中的重要性,详细讲解了Prim和Kruskal两种算法,分别通过对节点和边进行贪心操作来构建最小生成树。文中提供了实例题目的解析,包括Python代码实现,帮助读者深入理解这两种算法的工作原理。
摘要由CSDN通过智能技术生成

目录

一、前言

二、相关概念

1、最小生成树

2、Prim算法(对结点进行操作)

3、kruskal 算法(对边进行操作)

三、例题

1、修建公路(lanqiaoOJ题号1124)

1、Prim算法题解

2、Kruskal算法


一、前言

很久没更新了蓝桥杯算法栏目了,明天国赛了,浅更新一下,求最小生成树,相信大家都会,本文带大家来回顾一下这两个非常简单好用的算法。(贵在理解算法逻辑,代码什么的都是次要)

二、相关概念

1、最小生成树

  • 在无向图中,连通而且不含有圈(环路)的图,称为树。
  • 最小生成树MST:一个有n个结点的连通图的生成树是原图的极小连通子图,包含原图中的所有n个结点,并旦边的权值之和最小。
  • 两种算法:prim、kruskal

2、Prim算法(对结点进行操作)

  • 对点进行贪心操作:“最近的邻居一定在 MST 上”。
  • 从任意一个点 u 开始,把距离它最近的点 v 加入到 MST 中;下一步,把距离 {u, v} 最近的点 w 加入到 MST 中;继续这个过程,直到所有点都在 MST 中。

补充:1956年,Dijkstra在一篇论文中同时提出了这两个算法,两个算法的思想基本一样,都是基于贪心法来扩展结点,执行步骤十分相似,代码只有微小差别。

3、kruskal 算法(对边进行操作)

  • 对边进行贪心操作:“最短的边一定在 MST 上”。
  • 从最短的边开始,把它加入到 MST 中;在剩下的边中找最短的边,加入到 MST 中;继续这个过程,直到所有点都在 MST 中。

补充:

kruskal 算法的 2 个关键技术:

1)对边进行排序。

2)判断圈,即处理连通性问题。这个问题用并查集简单而高效,并查集是 kruskal 算法的实现基础。

三、例题

1、修建公路(lanqiaoOJ题号1124)

链接:用户登录

可能部分同学没办法进入到链接刷这道题,我把题目放上来。

题目描述

L 城一共有 N 个小区。

小明是城市建设的规划者,他计划在城市修 M 条路,每修建一条路都要支付工人们相应的工钱(需要支付的工钱 == 路的长度)。

然而小明所拿到的经费并不够支付修建 M 条路的工钱,于是迫于无奈,他只能将计划改变为修建若干条路,使得 N 个小区之间两两联通。

小明希望尽量剩下更多的经费投入到别的项目中,因此请你通过程序帮他计算出完成计划所需的最低开销。

输入描述

输入第一行包含三个正整数 N,M。

第 2 到 M+1 行每行包含三个正整数 u, v, w,表示 u↔v 之间存在一条距离为 w 的路。

1≤N≤10^5,0≤m≤3×10^5,1≤ui​,vi​≤N,0≤wi​≤10^9。

输出描述

输出占一行,包含一个整数,表示完成计划所需的最低开销。

若无法完成计划,则输出 −1。

输入输出样例

输入:

5 6
1 2 2
1 3 7
1 4 6
2 3 1
3 4 3
3 5 2

输出:

8

运行限制

  • 最大运行时间:3s
  • 最大运行内存:256M

1、Prim算法题解

python代码(AC):

import sys
from heapq import *
input=sys.stdin.readline

def prim():
    ans,cnt=0,0
    q=[]
    vis=[False for _ in range(n+1)]
    heappush(q,(0,1))
    while q and cnt<n:
        w,u=heappop(q)      #pop出距离集合最近的点u
        if not vis[u]:
            vis[u]=True
            ans+=w
            cnt+=1
            for v,w in e[u]:
                heappush(q,(w,v))
    if cnt!=n:
        print(-1)
    else:
        print(ans)
        
n,m=map(int,input().split())
e=[[] for _ in range(n+1)]
for i in range(m):
    u,v,w=map(int,input().split())
    e[u].append((v,w))
    e[v].append((u,w))
prim()

2、Kruskal算法

python代码(AC):

import sys
input=sys.stdin.readline

def init():
    for i in range(n+1):
        s.append(i)

def find(x):
    if s[x]==x:
        return x
    s[x]=find(s[x])
    return s[x]

def kruskal():
    cnt=0
    ans=0
    e.sort(key=lambda tup:tup[2])
    init()
    for i in range(m):
        x,y=e[i][0],e[i][1]
        e1,e2=find(x),find(y)
        if e1==e2:
            continue
        ans+=e[i][2]
        s[find(y)]=find(x)
        cnt+=1
        if cnt==n-1:
            break
    if cnt!=n-1:
        print(-1)
    else:
        print(ans)

e=[]
s=[]
n,m=map(int,input().split())       #顶点数,边数
for i in range(m):
    u,v,w=map(int,input().split())
    e.append((u,v,w))
kruskal()

根据这一题相信大家都能很好的理解Prim和Kruskal算法。

以上,求最小生成树(Kruskal算法和Prim算法)

煮好!

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

吕飞雨的头发不能秃

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值