最小生成树Prim与Kruskal算法的比较

文章探讨了最小生成树问题中Prim和Kruskal两种算法的区别和适用场景。Prim算法适用于点密集图,常采用邻接矩阵,而Kruskal算法在边较少时更优,使用并查集维护。可以结合点数和边数比例选择合适算法。文中还举例说明了两种算法的应用。
摘要由CSDN通过智能技术生成

最小生成树是图论问题中很基本的一个操作。常用的算法有Prim和Kruskal两种算法。本文对这两种算法稍作区别与讨论。


Prim算法是依赖于点的算法。它的基本原理是从当前点寻找一个离自己(集合)最近的点然后把这个点拉到自己家来(距离设为0),同时输出一条边,并且刷新到其他点的路径长度。俗称,刷表。
根据Prim算法的特性可以得知,它很适合于点密集的图。通常在教材中,对Prim算法进行介绍的标程都采用了邻接矩阵的储存结构。这种储存方法空间复杂度N^2,时间复杂度N^2。对于稍微稀疏一点的图,其实我们更适合采用邻接表的储存方式,可以节省空间,并在一定条件下节省时间。

Kruskal算法是依赖边的算法。基本原理是将边集数组排序,然后通过维护一个并查集来分清楚并进来的点和没并进来的点,依次按从小到大的顺序遍历边集数组,如果这条边对应的两个顶点不在一个集合内,就输出这条边,并合并这两个点。
根据Kruskal算法的特性可得,在边越少的情况下,Kruskal算法相对Prim算法的优势就越大。同时,因为边集数组便于维护,所以Kruskal在数据维护方面也较为简单,不像邻接表那样复杂。从一定意义上来说,Kruskal算法的速度与点数无关,因此对于稀疏图可以采用Kruskal算法。

那么究竟如何获得一种权衡的方法,既能应付稀疏图又能应付密集图呢?很简单,把两个算法都写到程序中,并且在行动之前判断一下点数边数的比例,如果达到某个临界值,就采用某种算法。当然,这样确实在实际行动中较为麻烦。



以下我们给出一道例题,用Prim和Kruskal算法分别解决该问题:

题目背景

农民约翰被选为他们镇的镇长!他其中一个竞选承诺就是在镇上建立起互联网,并连接到所有的农场。当然,他需要你的帮助。

题目描述

约翰已经给他的农场安排了一条高速的网络线路,他想把这条线路共享给其他农场。为了用最小的消费,他想铺设最短的光纤去连接所有的农场。

你将得到一份各农场之间连接费用的列表,你必须找出能连接所有农场并所用光纤最短的方案。每两个农场间的距离不会超过100000

输入输出格式

输入格式:
第一行: 农场的个数,N3<=N<=100)。

第二行..结尾: 后来的行包含了一个N*N的矩阵,表示每个农场之间的距离。理论上,他们是N行,每行由N个用空格分隔的数组成,实际上,
  • 4
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Prim算法Kruskal算法都是用于求解最小生成树的经典算法Prim算法的基本思想是从一个点开始,每次选择一个与当前生成树距离最近的点加入生成树中,直到所有点都被加入生成树为止。具体实现时,可以使用一个优先队列来维护当前生成树与未加入生成树的点之间的距离,每次选择距离最小的点加入生成树中。 Kruskal算法的基本思想是从边开始,每次选择一条权值最小且不会形成环的边加入生成树中,直到生成树中包含所有点为止。具体实现时,可以使用并查集来判断是否形成环。 下面是Prim算法Kruskal算法的C语言代码实现: Prim算法: ```c #include <stdio.h> #include <stdlib.h> #include <limits.h> #define MAX_VERTICES 1000 int graph[MAX_VERTICES][MAX_VERTICES]; int visited[MAX_VERTICES]; int dist[MAX_VERTICES]; int prim(int n) { int i, j, u, min_dist, min_index, sum = 0; for (i = 0; i < n; i++) { visited[i] = 0; dist[i] = INT_MAX; } dist[0] = 0; for (i = 0; i < n; i++) { min_dist = INT_MAX; for (j = 0; j < n; j++) { if (!visited[j] && dist[j] < min_dist) { min_dist = dist[j]; min_index = j; } } u = min_index; visited[u] = 1; sum += dist[u]; for (j = 0; j < n; j++) { if (!visited[j] && graph[u][j] < dist[j]) { dist[j] = graph[u][j]; } } } return sum; } int main() { int n, m, i, j, u, v, w; scanf("%d%d", &n, &m); for (i = 0; i < n; i++) { for (j = 0; j < n; j++) { graph[i][j] = INT_MAX; } } for (i = 0; i < m; i++) { scanf("%d%d%d", &u, &v, &w); graph[u][v] = graph[v][u] = w; } printf("%d\n", prim(n)); return 0; } ``` Kruskal算法: ```c #include <stdio.h> #include <stdlib.h> #include <limits.h> #define MAX_VERTICES 1000 #define MAX_EDGES 1000000 struct edge { int u, v, w; }; int parent[MAX_VERTICES]; struct edge edges[MAX_EDGES]; int cmp(const void *a, const void *b) { return ((struct edge *)a)->w - ((struct edge *)b)->w; } int find(int x) { if (parent[x] == x) { return x; } return parent[x] = find(parent[x]); } void union_set(int x, int y) { parent[find(x)] = find(y); } int kruskal(int n, int m) { int i, sum = 0; for (i = 0; i < n; i++) { parent[i] = i; } qsort(edges, m, sizeof(struct edge), cmp); for (i = 0; i < m; i++) { if (find(edges[i].u) != find(edges[i].v)) { union_set(edges[i].u, edges[i].v); sum += edges[i].w; } } return sum; } int main() { int n, m, i; scanf("%d%d", &n, &m); for (i = 0; i < m; i++) { scanf("%d%d%d", &edges[i].u, &edges[i].v, &edges[i].w); } printf("%d\n", kruskal(n, m)); return 0; } ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值