Prim最小生成树算法
刷题遇到一道Prim最小生成树算法的实现的题目,重新温习一下最小生成树算法:
首先本人不是很会画图,那就直接拿百度百科的图片来研究说明以下:图如下:
此算法用来求解一个包含图中所有顶点,且其边权值之和也为最小。如这个图我们可以找到以下边:AD, DF, AB, BE, EC, EG 这样的是包含所有的点且边长权值位最小。
那么算法是如何实现的呢?其实比较简单。那就是我们需要在每次找当前经过的所有结点中到其他可到达的结点的最小的路径。每次都去找这样一条路径并循环n- 1次,这样n个结点是必须至少要n - 1条边的。
那么我们现在考虑一下要存储我们需要的数据需要怎么存储呢?
首先,我们需要一个长度为结点个数的数组low,用这个数组来存储当前经历过的结点中到其他未经历过的结点的最小值。这个low的数组是需要不停更新的。
其次,我们还需要一个长度为结点个数的数组used来记录结点是否经过。我们同样需要一个长度为结点个数的数组closeset来记录这个到达该点的最小值是由哪个以经历过的结点发出的。
最后需要存储树的数据的话,我们需要一个长度为结点个数的数组来存储树的上下关系。
存储数据方式确定完毕以后下面是算法的实现:
/************************************************************************* > File Name: myPrim最小生成树.c > Author: zhanghaoran > Mail: 467908670@qq.com > Created Time: 2015年05月25日 星期一 12时10分05秒 ************************************************************************/ #include <stdio.h> #include <string.h> #define INF 1000000 //用INF表示不相邻的两个边 #define vertexes 7 typedef int Graph[vertexes][vertexes]; void Prim(Graph G, int count, int father[]){ int low[vertexes]; int closeset[vertexes]; int used[vertexes]; int i, j ,k, min; for(i = 0; i < count; i ++){ //初始化需要使用的四个数组,初始化所有数组为所有结点到v1这个结点的情况 low[i] = G[0][i]; used[i] = 0; closeset[i] = 0; father[i] = -1; } used[0] = 1; for(i = 0; i < count - 1; i ++){ j = 0; min = INF; for(k = 1; k < count; k ++) //在low这个数组中找最小的值 if(!used[k] && (low[k] < min)){ min = low[k]; j = k; //将该点记录在j中 } father[j] = closeset[j]; //此点父结点为closeset中与其到其最近的一个结点 printf("%d %d\n", j + 1, closeset[j] + 1); used[j] = 1; //将此点标记为经过 for(k = 0; k < count; k ++) //更新low这个数组,如果找打到在当前结点到其他未经过的点有更小值,立刻更新。 if(!used[k] && (G[k][j] < low[k])){ low[k] = G[j][k]; closeset[k] = j; } } } int main(void){ int i, j , weight; Graph G; int father[vertexes]; for(i = 0; i < vertexes; i++) for(j = 0; j < vertexes; j++){ scanf("%d", &G[i][j]); if(G[i][j] == 0) G[i][j] = INF; } Prim(G, vertexes, father); return 0; }回头将结合OJ相关题目来做进一步介绍