无向连通网的最小生成树

对于一个无向网(即带权无向图),生成树上各边权值之和称作这棵生成树的代价,最小代价生成树是各边权值综合最小的生成树,简称最小生成树。

一个无向连通网的最小生成树也可能不是惟一的,但总代价一定是最小的。构造无向连通网的最小生成树方法可以有多种,下面介绍Prim和Kruskal算法就是构造最小生成树的两种算法。

1.prim算法

prim算法是从连通网中的某一个顶点开始,以此作为生成树的初始状态,然后不断地将网中的其他顶点添加到生成树上,直到最后一个顶点添加到生成树上时得到最小生成树,其具体方法是:

(1).从网中的任一顶点开始,先把该顶点包含在生成树中,此时生成树只有一个顶点。
(2).找出一个端点在生成树中,另一个在生成树外的所有边,并把权值最小的边连同它所关联的另一个顶点添加到生成树中;当有两条及以上具有相同最小权值的边可供选择时,选择其中任意一条都可以。
(3).反复执行(2),直到所有顶点都包含在生成树中时止。
为了实现Prim算法,须设一个辅助数组closedge以记录每次选择的权值最小的边。数组元素closedge[i]对应于序号为i的顶点Vi,它包含两个域adjvex和lowcost.若Vi已在生成树上,则置closedge.lowcost=0;
若顶点Vi不在生成树上,用closedge[i].lowcost存放Vi与生成树上顶点构成的最小代价边的权值,而closedge[i].adjvex存放该边所关联的生成树上的另一顶点的序号。
设有n个顶点的无向连通图以邻接矩阵g存储,从序号为k的顶点Vk开始构造最小生成树,则辅助数组的初始情况为:
closedge[k].lowcost=0;
closedge[k].lowcost=g.adjmatrix[k,i];(i!=k且1<=i<=n)
closedge[k].adjvex=k;(i!=k且1<=i<=n)
然后从数组选出某一个j,它满足closedge[i].lowcost不等于0且是最小的值,将Vj添加到生成树上并修改closedge数组的值。如此不断进行下去,直到
全部的n个顶点都在生成树上,就得到了要求的最小生成树。下面给出Prim算法的形式化描述如下:


#define m 30//m为顶点的个数最大值
#define max 99//max为权上次上限值
void prim(mgraph g,int k,int n)//从顶点Vk出发构造有n个顶点的无向连通网g的最小生成树的Prim
{
    int i,j,min,p;
    struct{
              int adjvex;//定义序号域为整型
              int lowcost;//假定权值均为整型数
          }closedge[m];//定义辅助数组的基类型为结构体
    for(i=1;i<=n;i++)//辅助数组初始化
        if(i!=k)
        {
            closedge[i].adjvex=k;//填边在生成树一端的顶点序号
            closedge[i].lowcost=g.adjmatrix[k][i];//填边的权值
        }
    closedge[k].lowcost=0;//顶点Vk已在生成树中,修改辅助数组
    for(i=1;i<n;i++)
    {
        p=1;
        min=max;
        for(j=1;j<=n;j++)//选最小权值及对应顶点Vp
            if(closedge[j].lowcost!=0&&closedge[j].lowcost<min)
            {
                min=closedge[j].lowcost;//最小权值记在min
                p=j;//把与边相关的生成树外的顶点序号记在p中
            }
        printf("%d %d %d\n",closedge[p].adjvex,p,min);//输出最小边及权值
        closedge[p].lowcost=0;//将顶点Vp加入生成树中
        for(j=1;j<=n;j++)//修改辅助数组的相应值,以便下一次选最小权值的边
            if(g.adjmatrix[p][j]<closedge[j].lowcost)
            {
                closedge[j].lowcost=g.adjmatrix[p][j];//修改权值域
                closedge[j].adjvex=p;//记下边在生成树一端的顶点序号
            }
    }//选一条边及对应顶点结束
}

2.Kruskal算法

Kruskal算法是求无向连通网的最小生成树的另一种常用算法。它与prim算法不同,时间复杂度主要是与网中边的数量e相关为O(eloge),适用于求边稀疏的无向连通网的最小生成树。

Kruskal算法的思想为:

(1).将n个顶点看作是n个独立的连通分量,将e条边按权值大小由小到大排序。

(2).从权值最小的边开始依权值递增顺序查看每一条边,如果该边所依附的两个顶点在两个不同的连通分量上,则选定此边连接两个连通分量为一个连通分量,否则舍弃此边。

(3).反复执行(2),直到所有顶点都在同一个连通分量上为止,这个连通分量即所求的最小生成树。

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是使用Prim算法求给定无向连通最小生成树的示例代码: ```c #define MAXV 100 // 最大顶点数 #define INF 0x3f3f3f3f // 无穷大 int G[MAXV][MAXV]; // 存储的邻接矩阵 int d[MAXV]; // 存储到已选顶点集合的最小距离 int parent[MAXV]; // 存储每个顶点在最小生成树中的父节点 bool visited[MAXV]; // 标记顶点是否已被加入最小生成树中 int prim(int n, int start) { int sum = 0; memset(visited, false, sizeof(visited)); memset(d, INF, sizeof(d)); memset(parent, -1, sizeof(parent)); d[start] = 0; for (int i = 0; i < n; i++) { int u = -1; for (int j = 0; j < n; j++) { if (!visited[j] && (u == -1 || d[j] < d[u])) { u = j; } } visited[u] = true; sum += d[u]; for (int v = 0; v < n; v++) { if (!visited[v] && G[u][v] != INF && G[u][v] < d[v]) { d[v] = G[u][v]; parent[v] = u; } } } return sum; } ``` 其中,`G`是一个二维数组,存储无向连通的邻接矩阵;`d`是一个一维数组,存储到已选顶点集合的最小距离;`parent`是一个一维数组,存储每个顶点在最小生成树中的父节点;`visited`是一个一维数组,标记顶点是否已被加入最小生成树中。`n`是无向连通的顶点数,`start`是起始顶点。 代码中,首先初始化各数组。然后从起始顶点开始,遍历所有顶点,选择距离已选顶点集合最近的未加入最小生成树的顶点,将其加入最小生成树,并更新与该顶点相邻的未加入最小生成树的顶点的最小距离和父节点。最后返回最小生成树的权值和。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值