最小生成树 Kruskal 算法 和 Prim算法

来源:互联网 发布:node留言板 编辑:程序博客网 时间:2024/06/05 11:12


Kruskal 算法 和 Prim算法 是 最小生成树基础的两种算法:

本文章中的代码用c语言写的(不过头文件用了c++ 的尴尬,大家不要在意),  其实在 Kruskal 算法 里面对数据进行排序的时候 可以用 C++ 库函数 的 sort排序进行排序  ,不过这里面我写了一个 快排,用快排进行排序了!   在 Kruskal 算法 里面,用到了并查集的 查询 和 合并 两个函数,主要是用来检查某个节点是否用过!

Prim算法 如果你仔细研究的话你会发现,Prim算法  和 最短路 的 Dijkstra 的算法的思想比较相似,基本可以说Prim 运用了 最短路  Dijkstra 的思想!


先给出一组测试数据:

输入第一行有两个数 n 和 m,n 表示有n个城市,m表示有m条道路。接下来的m行,每行形容“a b c”用来表示一条路,意思是城市a 到城市 b 的路径长度为 c。


输入:6 92 4 113 5 134 6 35 6 42 3 64 5 71 2 13 4 91 3 2输出结果:19



//  Kruskal 算法:    这里的 Kruskal 算法 的时间复杂度是  O(nlog(n))#include <iostream>#include <algorithm>#include <cstring>#include <string>#include <cstdio>using namespace std;struct edge{int u;int v;int w;};struct edge e[110];int n,m;int f[7] = {0},sum = 0,Count = 0;void quicksort(int left,int right) // 快速排序 {int i,j;struct edge t;if(left > right)return;i = left;j = right;while(i != j){while(e[j].w >= e[left].w && i < j)j--;while(e[i].w <= e[left].w && i < j)i++;if(i < j){t = e[i];e[i] = e[j];e[j] = t;}}t = e[left];e[left] = e[i];e[i] = t;quicksort(left,i - 1);quicksort(i + 1,right);return;}int getf(int v)              //   并查集查找根节点 {if(f[v] == v)return v;else{f[v] = getf(f[v]);return f[v];}}int merge(int v,int u)         //  将两棵树合并 {int t1,t2;t1 = getf(v);t2 = getf(u);if(t1 != t2){f[t2] = t1;return 1;}return 0;}int main(){int i;scanf("%d%d",&n,&m);for(i = 1;i <= m;i++){scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);}quicksort(1,m); // 按照权值从小到大对边进行快速排序for(i = 1;i <= n;i++)       //  并查集根节点的初始化 {f[i] = i;} for(i = 1;i <= m;i++)          //  权值已经按照从小到大排序好了,所以可以直接将不在同一颗树的两颗树合并成一颗树 {if(merge(e[i].u,e[i].v)){Count++;sum += e[i].w;}if(Count == n - 1)     //    直到合并到 n - 1 次  ,也是就将 n 棵树树合并成一棵树,跳出循环,这个树就是最小生成树 break;}printf("%d\n",sum);return 0;}





//  Prim算法       该代码  的时间复杂度  为  O(n^2)  如果借助“堆”,然后使用邻接表来储存图的话时间可达到    O(nlog(n))#include <iostream>#include <algorithm>#include <cstring>#include <string>#include <cstdio> using namespace std;int main(){int n,m,i,j,k,min,t1,t2,t3;int e[7][7],dis[7],book[7] = {0};int inf = 99999999;int count = 0,sum = 0;scanf("%d%d",&n,&m);for(i = 0;i <= n;i++)      //  进行一个初始化 {for(j = 1;j <= n;j++){if(i == j)           //   自己到自己  权为 0 e[i][j] = 0;elsee[i][j] = inf;     //  自己到其他 权为 inf }}for(i = 1;i <= m;i++)         //  根据题里给的条件  更新相应的权值 {scanf("%d%d%d",&t1,&t2,&t3);e[t1][t2] = t3;e[t2][t1] = t3;}// 初始化dis数组,这里是1号顶点到各个顶点的初始距离,因为当前生成树中只有1号顶点 for(i = 1;i <= n;i++){dis[i] = e[1][i];}book[1] = 1; //  book 标记该顶点是否已经加入生成树count++;while(count < n){min = inf;for(i = 1;i <= n;i++)    //  寻找生成树到 i 节点的最小长度的路径 {if(book[i] == 0 && dis[i] < min){min = dis[i];j = i;}}book[j] = 1;        //  找到后将 i 节点接到 生成树上 count++;sum += dis[j];     //  总路径长度加上新增加的长度,更新总长度 //  扫描当前顶点 j 所有的边,再以j为中间点,更新生成树到每一个非树顶点的距离 for(k = 1;k <= n;k++){if(book[k] == 0 && dis[k] > e[j][k])dis[k] = e[j][k];}} printf("%d\n",sum);return 0;}


0 0
原创粉丝点击