最小生成树——prim算法
最近在复习数据结构和算法,复习到最小生成树的的时候发现当时学的时候并没有太多的深入学习这个部分,差不多都忘光了。
而在复习prim算法的过程也发现其实对于这个算法其实思路是挺容易理解的,但可能会卡在代码实现。所以我打算结合代码来理解prim算法。
算法思路
虽说是结合代码,但这个算法的总体思路还是要有了解的。
- 首先,选择图中任意一点作为树的初始点,并加入到集合U中。
- 在集合U中,找和其他顶点的最短距离的边,并把该最短距离边的顶点加入到U中。
- 刷新集合U距离其他顶点的最短距离。
- 重复2,3直至所有顶点均包含(这里我们只讨论连通图)
代码
这里我先把代码放出来,然后再逐步分析
//prim算法
int prim(int v,int n){//v是初始顶点,n是顶点数
int sum = 0,k;
bool book[n + 1];
memset(book,0,n + 1);
book[v] = 1;//标记是否存在集合U中
dist[v] = 0;//U距离其他顶点的最短距离
for(int i = 1;i <= n;i++){
dist[i] = all[v][i];
}
for(int i = 0;i < n - 1;i++){
int min = inf;
for(int j = 1;j <= n;j++){
if(dist[j] < min && !book[j]){
k = j;
min = dist[j];
}
}
book[k] = 1;
sum += min;
for(int j = 1;j <= n;j++){
if(all[k][j] < dist[j] && !book[j]){
dist[j] = all[k][j];
}
}
}
return sum;
}
代码解析
首先,我们要定义我们要用到的数据。
sum——最小生成树的距离之和(总权数)
k——记录中间产生的最小距离边的顶点
book[]——标记某个顶点是否存在于集合U中,默认全为0
dist[]——记录集合U到其他顶点的最短距离
然后,我们进行思路的第一步:
把选择的顶点v加入到集合U中,因此先标记v在集合中,
book[v] = 1;
这时集合U只有v一个顶点,所以U距离其他顶点的距离就是v距离其他顶点的距离,所以将v和其他点的距离直接更新到dist数组中。
for(int i = 1;i <= n;i++){
dist[i] = all[v][i];
}
准备工作做好后,我们可以开始第二步:
这里先让最小值等于无穷大
int min = inf;
for(int j = 1;j <= n;j++){
if(dist[j] < min && !book[j]){
k = j;
min = dist[j];
}
}
然后遍历dist数组找最小值,就是找U和其他点最短距离。但if条件不要忘了该点要符合不存在集合U中,所以该点顶点应该是book标记为0。
遍历后该点记录为k,然后对该点进行标记,同时可以把改距离也加入到结果距离中。
book[k] = 1;
sum += min;
最后,就是进行对集合U的刷新了:
因为我们知道集合U本身就是到其他顶点的最短距离,所以只要比较集合U和加入的K顶点,到同一个顶点的距离谁最小就可以了。
然后更新的时候更新非U中的顶点,所以if条件也是更新没有标记的点。
for(int j = 1;j <= n;j++){
if(all[k][j] < dist[j] && !book[j]){
dist[j] = all[k][j];
}
}
将这个步骤重复 顶点数 - 1次就能得出最小生成树了