1.问题
在一给定的无向图G = (V,E) 中,(u,v) 代表连接顶点u与顶点v的边,w(u, v) 代表此边的权,若存在 T 为 E 的子集且为无循环图,使得的 w(T) 最小,则此 T 为 G 的最小生成树。
2.解析
1).输入:一个加权连通图,其中顶点集合为V,边集合为E;
2).初始化:Vnew = {x},其中x为集合V中的任一节点(起始点),Enew = {},为空;
3).重复下列操作,直到Vnew = V:
在集合E中选取权值最小的边 <u, v>,其中u为集合Vnew中的元素,而v不在Vnew集合当中,并且v∈V(如果存在有多条满足前述条件即具有相同权值的边,则可任意选取其中之一);
将v加入集合Vnew中,将 <u, v> 边加入集合Enew中;
4).输出:使用集合Vnew和Enew来描述所得到的最小生成树。
3.设计
#define NUM 20 //数组容量
#define INFINITY 65535 //象征无穷大
#define VRType int //权值类型
#define VertexType int //顶点类型
//存储数组
typedef struct {
VRType arcs[NUM][NUM]; //邻接矩阵map存储连通图,map[u][v]表示顶点u到v的权值
VertexType vexnum,arcnum; //记录图的顶点数和边数
}MGraph;
typedef struct {
VertexType adjvex;//记录权值最小的边的起始点
VRType lowcost;//记录该边的权值
}closedge[NUM];
//在辅助数组中找出权值最小的边的数组下标,就可以间接找到此边的终点顶点。
closedge dist;//创建一个全局数组,因为每个函数中都会使用到
mindist(MGraph G,closedge dist);
//start结点为初始结点
void Prim(MGraph G,VertexType start)
{
for(循环n次){
//遍历除start以外的结点,来记录与start相关的权值,没有和start连线的权值为无穷大
}
//由于起始点已经归为最小生成树,所以dist数组对应位置的权值为0,这样,遍历时就不会被选中
dist[start].lowcost=0;
for(循环n-1次)
{
//在dist数组找出权值最小的边,并记录下标pos
int pos=mindist(G,dist);
//归入最小生成树的顶点的dist数组中的权值设为0
dist[pos].locost=0;
//由于此时树中新加入了一个顶点,需要判断,由此顶点出发,到达其它各顶点的权值是否比之前记录的权值还要小,如果还小,则更新
for(int i=1;i<=n;i++){
//由于之前归入最小生成树的顶点的dist数组中的权值设为0
//设初始点为1,且1、2已为生成树内的点,3为新加入的点的话,1-2权值为0,1-3的权值为0
//i=1时,dist[1]为0<G.arcs[3][1]
//i=2时,dist[2]为1-2权值为0,G.arcs[3][2]为3-2权值>0,因此不会出现闭环情况
if(dist[i].lowcost>G.arcs[pos][i]){
dist[i].lowcost=G.arcs[pos][i];
}
}
}
}
4.源码
https://github.com/8455580/homework/blob/main/1/Prim.c
1.问题
在一给定的无向图G = (V,E) 中,(u,v) 代表连接顶点u与顶点v的边,w(u, v) 代表此边的权,若存在 T 为 E 的子集且为无循环图,使得的 w(T) 最小,则此 T 为 G 的最小生成树
2.解析
记Graph中有v个顶点、e个边
新建图Graphnew,Graphnew中拥有原图中同样的e个顶点,但没有边
将原图Graph中全部e个边按权值从小到大排序
循环:从权值最小的边開始遍历每条边 直至图Graph中全部的节点都在同一个连通分量中
如果这条边连接的两个节点于图Graphnew中不在同一个连通分量中
增加这条边到图Graphnew中
3.设计
#include <stdio.h>
#include <stdlib.h>
#define NUM 20 //最大容量
#define VertexType int
typedef struct edge{
VertexType adjvex; //起始点
VertexType end; //终点
VertexType arcs; //权值
} edge[NUM];
//定义辅助数组
typedef struct {
VertexType value;//顶点数据
int sign;//每个顶点所属的集合
}Dist[NUM];
Dist dist;
int main(){
int arcnum,vexnum,i,j;
edge edges;
//创建连通图
CreateUDN(&edges,&vexnum,&arcnum);
//对连通网中的所有边进行升序排序,结果仍保存在edges数组中
//创建一个空的结构体数组,用于存放最小生成树
edge minTree;
//设置一个用于记录最小生成树中边的数量的常量
int num=0;
//遍历所有的边
for (i=0; i<arcnum; i++) {
int initial= edges[i].adjvex;
int end= edges[i].end;
//如果顶点位置存在且顶点的标记不同,说明不在一个集合中,不会产生回路
if (initial!=-1&& end!=-1&&dist[initial].sign!=dist[end].sign) {
//记录该边,作为最小生成树的组成部分
minTree[num]=edges[i];
//计数+1
num++;
//将新加入生成树的顶点标记全部更改为一样的
//如果选择的边的数量和顶点数相差1,证明最小生成树已经形成,退出循环
}
}
//输出语句
return 0;
}
4.源码
https://github.com/8455580/homework/blob/main/1/Kruskal.c