标签:
最小生成树是指从连好的图中(有n个点,多于(n-1)条边)选取n-1条边将n个点相互连接,并使得此树的总权值最小。完成此构造的方法著名的有两种,一个是kruskal算法,此算法是对每条边的权值进行排序,然后依次选取小的边添加到树上,并保证是一棵树(即不能产生回路)。另外一个就是prim算法,此算法是从点的角度来考虑。首先用map[][]二维数组存放两点间的权值,另外使用一个一维数组lowcost[]来存放与所选取的点相关联的权值,另外也使用一个mark[]数组用来标记已使用过的点。基本思想与最短路径中dijkstra算法十分相似。
prim算法基本思想:
从连通网络N={V,E},中选取一点S出发,选择与它相关联并且权值最小的边(S,V),将其顶点加入到生成树的顶点集合U中。以后每一步都选取一个不在顶点集合U中的点,使其到U的权值最小,然后将其加入到顶点集合U中。如此下去,直到网络中所有顶点均加入到生成树的顶点集合U中为止。
用prim算法构造最小生成树的过程:
假设在构造过程中,树的顶点集U与边集均为红色,U集合之外的点为蓝色,连接红与蓝的边为紫色,则 最短的紫色边就是当前要寻找的边。每选取一个顶点就需对剩下的顶点作调整,更新其到树的顶点集U的距离。具体请参考代码:
#include<stdio.h> #include<string.h> #define INF 0x3f3f3f3f int map[1010][1010]; int lowcost[1010]; int mark[1010]; int n,m; int prim() { int vir,min,sum=0; for(int i=1;i<=n;i++) //将标记数组初始化为0,lowcost数组存放与起点1有关的点的权值 { mark[i]=0; lowcost[i]=map[1][i]; } mark[1]=1; //将起点标记 for(int i=1;i<n;i++) //有n个点,所以需查找n-1次 { min=INF; for(int j=1;j<=n;j++) //查找距树集合权值最小的点 { if(!mark[j]&&lowcost[j]<min) { min=lowcost[j]; vir=j; } } if(min==INF) break; sum+=min; //最小权值累加 mark[vir]=1; //标记已找到过的点 //更新各点距树集合的距离 for(int j=1;j<=n;j++) { if(!mark[j]&&lowcost[j]>map[vir][j]) { lowcost[j]=map[vir][j]; } } } return sum; //返回最小生成树的权值 } int main() { while(scanf("%d%d",&n,&m)!=EOF) { for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) //将map数组初始化为较大的值 map[i][j]=INF; for(int i=0;i<m;i++) { int x,y,cost; scanf("%d%d%d",&x,&y,&cost); if(map[x][y]>cost) //记录点与权值,若有重复取权值小的 { map[x][y]=cost; map[y][x]=cost; } } printf("%d\n",prim()); //输出此最小生成树的权值 } return 0; }
版权声明:本文为博主原创文章,未经博主允许不得转载。
标签:
原文地址:http://blog.csdn.net/lsgbb/article/details/47748001