1.问题
如何求一个包含有原图所有n个结点的且所有边的代价和最小的极小连通子图。
2.解析
构造最小生成树有两种算法模式。
第一种是Kruskal算法。它的要点就是选边。即从最短的边开始生成森林,最后连成树。简单的步骤:
1.图中的所有边按权重从小到大排序;
2.图中的n个顶点看成独立的n棵树组成的森林;
3.按权重从小到大选择边,所选的边连接的两个顶点应属于两颗不同的树,则成为最小生成树的一条边,并将这两颗树合并作为一颗树。
4.重复3,直到所有顶点都在一颗树内或者有n-1条边为止。
以下面为例。所有边按照权重排序为1.1.2.2.4.4.5.6.7.8.10,每一个顶点为独立的森林。然后一步步根据权重的顺序选择边。第一步选择v1和v4连接的边,权重为1。第二步选择v6和v7连接的边,权重为1。以此类推,等到选择第二条权重为4的边时,发现连接后会形成闭环或者说是两个顶点都被选中过,就不选择,跳到下一个边去。一直循环往复,直到所有顶点都在一颗树内或者有n-1条边为止。

第二种是prim算法。它的要点就是选点。即从某一个点出发,在两个点之间选择权重最小的一条边,连接两个点,加入生成树之中。简单的步骤:
1.图的所有顶点集合为VV。
2.在顶点集合中能够组成的边中,选择一条代价最小的边,加入到最小生成树中。
3.重复上述步骤,直到最小生成树有n-1条边或者n个顶点为止。
以下图为例,先选择v1点,在v1的邻接点中选择权重最小的v4。然后再v1和v4的共同邻接点中继续选择权重最小的点,即v2或v3,这里选择了v2。然后在三者的并查集中再次选择,即v3。继续重复上述流程,直到最小生成树有n-1条边或者n个顶点为止。

3.设计
1.1
void kruskal(edge e[],int m,int n){
int i,j,v1,v2,s1,s2,k,sum=0;
int set[m+1];
//构建顶点编号集
for(i=1;i<=m;i++){
set[i]=i;
}
//最小生成树的第k条边
k=1;
//边的下标
j=0;
while(k<=n){
if (j>n) break;
//先获取j边的邻接点,以及所属的集合编号
v1=e[j].v1;
v2=e[j].v2;
s1=set[v1];
s2=set[v2];
//当两点的集合不同时,表示该边为生成树的一条边
if(s1!=s2){
printf("V%d-V%d=%d\n",v1,v2,e[j].w);
sum+=e[j].w;
k++; //最小生成树的边数增加
if(k>=n) break;
for(i=1;i<=m;i++){
if(set[i]==s2) set[i]=s1; //表示该点已经加入v1的集合中,同一集合
}
}
j++; //下一条边
}
printf("最小权值之和=%d\n",sum);
}
1.2

2.1
void prim(int graph[][MAX],int n){
int mincost[MAX];
int mst[MAX];
int i,j,min,minid,sum=0;
for(i=2;i<=n;i++){
//以顶点1为起始点,并存放顶点1到邻接点的路径。
mincost[i]=graph[1][i];
mst[i]=1;
}
mst[1]=0;
for (i=2;i<=n;i++){
min=MAXCOST;
minid=0;
for(j=2;j<=n;j++){
//找出权重最短的路径和id
if(mincost[j]<min&&mincost[j]!=0){
min=mincost[j];
minid=j;
}
}
printf("V%d-V%d=%d\n",mst[minid],minid,min);
//对权重求和
sum+=min;
//对最短路径的权重置0;
mincost[minid]=0;
for(j=2;j<=n;j++){
//路径更新
if(graph[minid][j]<mincost[j]){
mincost[j]=graph[minid][j];
mst[j]=minid;
}
}
}
printf("最小权重之和=%d\n",sum);
}
2.2

4.分析
因为prim算法需要选点,通过遍历所有点集选出权重小的路径,并加入另一个点,再次遍历并查集,所以时间复杂度与顶点数v有关。Prim算法的复杂度为T=O(|V|^2),适用于边数较多的稠密图
因为kruskal算法需要选边,通过先对边的权重进行升序排序,,在升序遍历权重对应的点,加入没有被选择过的点,所以时间复杂度与边数e有关。Kruskal算法的复杂度为T = O(|E|log|E|) 用于边数较少的稀疏图
5.源码
https://github.com/Chenzh0205/Algorithm/tree/main/%E4%BD%9C%E4%B8%9A1
6.参考资料
1.数据结构课程ppt
2.最小生成树构造算法–Prim算法,Kruskal算法(C语言)
本文介绍了两种构造最小生成树的方法:Kruskal算法和Prim算法。Kruskal算法通过选取权重最小的边逐步构建生成树,而Prim算法则从某个顶点出发,每次选择代价最小的边来扩展生成树。两种算法分别适用于稀疏图和稠密图。
3271

被折叠的 条评论
为什么被折叠?



