最小生成树之 prim & kruskal
2015-10-25 11:29
281 查看
最小生成树:
给定一个带权的 n 个结点的无向连通图,选取一个包含原图中的所有 n 个结点,并且保持图连通的,所有边的权值和最小。
求最小生成树的算法:
a:Kruskal 算法
图的存贮结构采用边集数组,该方法是按边进行连通的,类似一个开始为空的边集,每次选出不在集合中的权重最小的边,判断是否构成回路,若无,将该边加入到边集中,权值相等的边在数组中排列次序可以是任意的,该方法对于边相对比较多的不太实用,会浪费时间。
b:prim 算法
图的存贮结构采用邻接矩阵。该方法是按各个顶点连通的步骤进行的,需要一个开始为空集的顶点集,之后将已连通的顶点陆续加入到集合中,直到顶点集中中包含了所有顶点,如此得到所需的最小生成树。
Kruskal 算法:
方法:将图(n 个结点)中的所有边按权值从小到大排序,依次拿出一条边,若选边后不形成回路则选择该边,否则除去该边,依次选择(n -1)条边,即得最小生成树。
第一步,选择第一条边(权值为1)
第二步:选第二条边(权值为2)
第三步:选第三条边(权值为3)
第四步:选第四条边(权值为4)
第五步:选第五条边(权值为5)(但是要选择当前未连通的,例如3和4的权值也为5但此时3和4 已连通所以就不要选择这条边,而选择2和3
Prim 算法:
方法:从指定顶点开始将它加入集合中,然后将集合内的顶点与集合外的顶点所构成的边中选取权值最小的一条边作为生成树的边,并将集合外的那个顶点加入到集合中
,表示该顶点已连通,然后继续通过此方式选点,直到所有点都加入都集合中,即得最小生成树。
例在下图中从1点出发求最小生成树
先写出其邻接矩阵
第一步:从1开始,1进集合,找与集合外所有点所构成的边中权值最小的边
(1,2)-6 (1,4)-5 (1,3)-1
所以取(1,3)这条边
第二步:3进集合,1,3与2,4,5,6构成的最小边为(1,4)-5 (3,6)-4
所以取(3,6)边
第三步:6进集合,1,3,6与2,4,5构成的各最小边(1,2)-6 (3,2)-5 (6,4)-2
所以取(6,4)边
第四步:4进集合,1,3,6,4与2,5构成的各最小边(1,2)-6 (3,2)-5 (6,5)-6
所以取(3,2)边
第五步:2进集合,1,3,6,2,4与5构成的各最小边(2,5)-3
取(2,5)边
当然这里程序实现的时候要有更新最小权值的步骤
给定一个带权的 n 个结点的无向连通图,选取一个包含原图中的所有 n 个结点,并且保持图连通的,所有边的权值和最小。
求最小生成树的算法:
a:Kruskal 算法
图的存贮结构采用边集数组,该方法是按边进行连通的,类似一个开始为空的边集,每次选出不在集合中的权重最小的边,判断是否构成回路,若无,将该边加入到边集中,权值相等的边在数组中排列次序可以是任意的,该方法对于边相对比较多的不太实用,会浪费时间。
b:prim 算法
图的存贮结构采用邻接矩阵。该方法是按各个顶点连通的步骤进行的,需要一个开始为空集的顶点集,之后将已连通的顶点陆续加入到集合中,直到顶点集中中包含了所有顶点,如此得到所需的最小生成树。
Kruskal 算法:
方法:将图(n 个结点)中的所有边按权值从小到大排序,依次拿出一条边,若选边后不形成回路则选择该边,否则除去该边,依次选择(n -1)条边,即得最小生成树。
第一步,选择第一条边(权值为1)
第二步:选第二条边(权值为2)
第三步:选第三条边(权值为3)
第四步:选第四条边(权值为4)
第五步:选第五条边(权值为5)(但是要选择当前未连通的,例如3和4的权值也为5但此时3和4 已连通所以就不要选择这条边,而选择2和3
#include<stdio.h> #include<string.h> #include<algorithm> #define N 110 using namespace std; int pre ={0}; struct node { int r1,r2; int p; }road ; int cmp(node a,node b) { return a.p<b.p; } int find(int x) { return x==pre[x]?x:pre[x]=find(pre[x]); } int main() { int n,m,f1,f2,pm,i,flag; while(scanf("%d%d",&n,&m)&&n) { pm=flag=0; for(i=1;i<=m;++i)pre[i]=i; for(i=0;i<n;++i) { scanf("%d%d%d",&road[i].r1,&road[i].r2,&road[i].p); } //Kruskal算法 sort(road,road+n,cmp);//排序 for(i=0;i<n;++i)//选边 { f1=find(road[i].r1); f2=find(road[i].r2); if(f1!=f2)//若无构成回路则选择该边 { pre[f1]=f2;pm+=road[i].p;//pm为最小生成树的最小权值总和 } } for(i=1;i<=m;++i)//判断此时是否为一个合格的最小生成树,即是否连通 { if(i==find(i))flag++; } if(flag>1)printf("?\n"); else printf("%d\n",pm); } return 0; }
Prim 算法:
方法:从指定顶点开始将它加入集合中,然后将集合内的顶点与集合外的顶点所构成的边中选取权值最小的一条边作为生成树的边,并将集合外的那个顶点加入到集合中
,表示该顶点已连通,然后继续通过此方式选点,直到所有点都加入都集合中,即得最小生成树。
例在下图中从1点出发求最小生成树
先写出其邻接矩阵
第一步:从1开始,1进集合,找与集合外所有点所构成的边中权值最小的边
(1,2)-6 (1,4)-5 (1,3)-1
所以取(1,3)这条边
第二步:3进集合,1,3与2,4,5,6构成的最小边为(1,4)-5 (3,6)-4
所以取(3,6)边
第三步:6进集合,1,3,6与2,4,5构成的各最小边(1,2)-6 (3,2)-5 (6,4)-2
所以取(6,4)边
第四步:4进集合,1,3,6,4与2,5构成的各最小边(1,2)-6 (3,2)-5 (6,5)-6
所以取(3,2)边
第五步:2进集合,1,3,6,2,4与5构成的各最小边(2,5)-3
取(2,5)边
当然这里程序实现的时候要有更新最小权值的步骤
#include<cstdio> #include<cstring> #define inf 0x3f3f3f3f using namespace std; int m,map[110][110]; int vis[110],rec[110]; void prim() { int mark,minw,cnt=0,fe=0; vis[1]=1; for(int i=1;i<=m;++i) rec[i]=map[1][i];//记录其他点与指定顶点的边的权值 while(1) { minw=inf; mark=0; for(int i=1;i<=m;++i) { if(!vis[i]&&rec[i]<minw)//未进入集合中且当前权值最小 { minw=rec[i]; mark=i; } } if(!mark)//若再找不到这样条件的边即退出循环 break; fe+=minw;//权值总和 cnt++;//所选顶点的个数 vis[mark]=1; for(int i=1;i<=m;++i) { if(!vis[i]&&rec[i]>map[mark][i])//更新未进入集合的点与集合中的点的最小权值(这里不明白的话要动手自己模拟画一下 rec[i]=map[mark][i]; } } if(cnt!=m-1)//若不包括所有顶点则不是最小生成树 printf("?\n"); else printf("%d\n",fe); } int main() { int n,a,b,f; while(scanf("%d%d",&n,&m)&&n) { memset(vis,0,sizeof(vis)); memset(rec,0,sizeof(rec)); memset(map,inf,sizeof(map)); for(int i=0;i<n;++i) { scanf("%d%d%d",&a,&b,&f); if(f<map[a][b])//邻接矩阵 map[a][b]=map[b][a]=f; } prim(); } return 0; }
相关文章推荐
- Ubunte 11.4 下安装 SSH遇到的问题
- JSP三大指令
- 关于在JSP中页面展示报错调试的一些问题归纳(持续更新中...)
- C# CreateProcess的测试
- Exynos 4412启动流程分析
- poj Substrings 1226 (KMP&&枚举)
- 一个线性优化问题--仓库配货
- 一个线性优化问题--仓库配货
- GIS学习笔记之Arcgis监督分类
- 递归
- Leetcode119: Longest Substring Without Repeating Characters
- Cordys containner JMX 监控
- AndroidStudio环境下导出APK
- 计算机网络重要知识点
- 类的static成员函数问题
- 将php分页类YII绑定框架,就需要改变风格的基础
- Lightoj 1148 - Mad Counting (暴力分块)
- 分页查询
- Hadoop前篇
- 13章 类继承练习