1,何为最小生成树
一个有 n 个结点的连通图的生成树是原图的极小连通子图,且包含原图中的所有 n 个结点,并且有保持图连通的最少的边(n-1条)。
最小生成树可以用kruskal(克鲁斯卡尔)算法或prim(普里姆)算法求出。
2.kruskal(克鲁斯卡尔)算法
此算法可以称为“加边法”,初始最小生成树边数为0,每迭代一次就选择一条满足条件的最小代价边,加入到最小生成树的边集合里。
- 把图中的所有边按代价从小到大排序;
- 把图中的n个顶点看成独立的n棵树组成的森林;
- 按权值从小到大选择边,所选的边连接的两个顶点ui,viui,vi,应属于两颗不同的树,则成为最小生成树的一条边,并将这两颗树合并作为一颗树。
- 重复(3),直到所有顶点都在一颗树内或者有n-1条边为止。
核心代码:
这里在生成图的时候利用的是边集数组,并且已经是按权值从小到大排好序的。
int Find(int *parent, int f)
{
//从下标f开始寻找parent数组中元素为0的下标
while (parent[f]>0)
{
f = parent[f];
}
return f;
}
//最小生成树,克鲁斯卡尔算法
void Kruskal(MGraph *G)
{
int parent[MAXVERTEX];//存放最小生成树的顶点
for (int i = 0; i < G->numvertex; i++)
{
parent[i] = 0; //初始化全部为0,
}
int m, n;
for (int i = 0; i < G->numedges; i++)
{
n = Find(parent, G->edges[i].begin); //从该边的起点开始寻找parent数组中为0的元素的下标,
m = Find(parent, G->edges[i].end);//从该边的终点点开始寻找parent数组中为0的元素的下标,
if (n != m)//如果m=n说明如果连接这条边,则从该边的起点和终点最终都会到达同一顶点,即有环
{
parent[n] = m;
printf("(%d,%d) %d\t", G->edges[i].begin, G->edges[i].end, G->edges[i].wight);//打印边和权值
}
}
3,prim(普里姆)算法
此算法可以称为“加点法”,每次迭代选择代价最小的边对应的点,加入到最小生成树中。算法从某一个顶点s开始,逐渐长大覆盖整个连通网的所有顶点。
1,图的所有顶点集合为VV;初始令集合u={s},v=V−uu={s},v=V−u;
2,在两个集合u,vu,v能够组成的边中,选择一条代价最小的边(u0,v0)(u0,v0),加入到最小生成树中,并把v0v0并入到集合u中。
3,重复上述步骤,直到最小生成树有n-1条边或者n个顶点为止。
核心代码:
void prime(MGraph G)
{
//用的无向图,说起点终点是为了好描述
//mst[i]:表示对应lowcost[i]的起点,
//即说明边<mst[i],i>是MST(最小生成树)的一条边,
//当mst[i]=0表示起点i加入MST
int mst[MAXSIZE];
//表示以i为终点的边的最小权值,
//当lowcost[i]=0说明以i为终点的边的最小权值=0,
//也就是表示i点加入了MST
int lowcost[MAXSIZE];
lowcost[0] = 0;
mst[0] = 0;
//初始化lowcost为邻接矩阵第一行的权值
//mst全部存放下标为0的顶点
for (int i = 1; i < G.numvertex; i++)
{
lowcost[i] = G.edges[0][i];
mst[i] = 0;
}
//找到第i行权值最小的边的下标
for (int i = 1; i < G.numvertex; i++)
{
int min = INFINITY;//最小值先初始化为65535,代表无连接
int k = 0;//k为权值最小的边的终点
for (int j = 1; j < G.numvertex; j++)
{
//找到第i行权值最小的边,记录终点的下标
if (lowcost[j]!=0&&lowcost[j]<min)
{
min = lowcost[j];
k = j;
}
}
lowcost[k] = 0;
//打印当前顶点中权值最小的边
printf("(%d,%d)", mst[k], k);
//遍历第k行的所有权值
for (int j = 1; j < G.numvertex; j++)
{
if (lowcost[j] != 0 && G.edges[k][j] < lowcost[j])
{
lowcost[j] = G.edges[k][j];
mst[j] = k;
}
}
}
}