图-最小生成树-Prim与Kruskal算法

本文介绍了最小生成树的性质和两种经典算法:Prim算法和Kruskal算法。Prim算法采用贪心策略,每次从未访问的顶点中选择与已访问集合最近的顶点,直到所有顶点被包含。Kruskal算法则按边权从小到大选择,通过并查集判断边是否构成环。Prim适合稠密图,Kruskal适合稀疏图。
摘要由CSDN通过智能技术生成

最小生成树


最小生成树(Minimum Spanning Tree,MST)是在一个给定的无向图G(V,E)中求一棵树 T,使得这棵树拥有图 G中的所有顶点,且所有边都是来自图 G 中的边,并且满足整棵树的边权之和最小。

最小生成树有三个性质需要掌握:

  • 最小生成树是树,因此其边数等于顶点数减 1,且树内一定不会有环
  • 对给定的图G(V,E),其最小生成树可以不唯一,其边权之和一定是唯一的
  • 由于最小生成树是无向图上生成的,因此其根结点可以使这棵树上的任意一个结点。

一般来说,如果题目中涉及最小生成树本身的输出,为了让最小生成树唯一,一般都会直接给出根结点。

求解最小生成树一般有两种算法:Prim 算法和 Kruskal 算法,都采用了贪心的思想,只是贪心的策略不一样。

Prim算法

基本思想

对于图 G(V, E) 设置集合 S,存放已经被访问的顶点,然后每次从集合 V-S 中选择集合 S 的最短距离最小的一个顶点(记为 u),访问并加入集合 S。之后,令顶点 u 为中介点,优化所有从 u 能到达的顶点 v 与集合 S 之间的最短距离。这样的操作执行 n 次(n为顶点个数),直到集合 S 已经包含所有顶点。

也就是执行 n 次下面两个步骤:

  • 每次从集合 V - S 中选择与集合 S 最近的一个顶点(记为 u),访问 u 并将其加入集合 S,同时把这条离集合 S 最近的边加入最小生成树中。
  • 令顶点 u 作为集合 S 与集合 V-S 连接的接口,优化从 u 能到达的未访问顶点 v 与集合 S 的最短距离。

可以看到 Prim 算法的思想与最短路径中 Dijkstra 算法的思想几乎相同,只是在设计最短距离的时候用集合 S 代替了 Dijkstra 中的起点 s。

具体实现

prim 算法需要实现两个关键的概念,即集合 S 的实现、顶点Vi 与集合 S 的最短距离。

  • 集合 S 的实现方法和 Dijkstra 中相同,即使用一个 bool型数组 vis[] 来表示顶点是否已被访问。
  • 不妨令 int 型数组 d[] 来存放顶点 Vi 与集合 S 的最短距离。初始时除了起点 s 的d[s] 赋为0,其余顶点都赋值为一个很大的数 INF,即不可达。

可以看到 prim 算法与 **Dijkstra **算法使用的思想几乎完全相同,只有在数组 d[] 的含义上有所区别。在 Dijkstra 中 d[] 含义为起点 s 到达 Vi 的最短距离,在 prim 算法中 d[] 含义为顶点 Vi 到集合 S 的最短距离,二者的区别仅仅在于最短距离是顶点 Vi 针对的是起点s还是集合V。

所以伪代码和 Dijkstra 很像:

// 数组 d 为顶点与集合 S 的最短距离
void Prim(G, d[]) {
   
  初始化;
  for(循环 n 次) {
   
    u = 使 d[u] 最小的还未访问的顶点的标号;
    记 u 已经被访问;
    for(从 u 出发能到达的所有顶点 v) {
   
      if(v 未被访问 && 以 u 为中介点使得 v 与集合 S 的最短距离 d[v] 更优) {
   
        将 G[u][v] 赋值给 v 与集合 S 的最短距离 d[v]}
    }
  }
}

具体实现:

邻接矩阵版
const int maxn = 1000;	// 最大顶点数
const INF = 1e9;

int n, G[maxn][maxn];	// n 为顶点数
int d[maxn];					// 顶点与 S 的最短距离
bool vis[maxn] = {
   false};	// 标记数组

int prim(int s)
{
   		// s 号为默认初始点,函数返回最小生成树的边权之和
  fill(d, d+maxn, INF);	// fill 函数整个数组赋值为 INF
  d[s] = 0;	// 只有顶点到集合 S 的距离为 0&#
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值