最小生成树

算法一:Prim算法(可称为加点法)

   点集记为v。 定义一个集合U,来存储已经在生成树中的点。v-u是未在生成树中的点。定义一个closedge数组,分为两个区域,一个存储最小边在u中的顶点,另一个存储最小边的权值。将初始顶点加入U中,初始化closedge数组。选择最小边closedge[k],将K加入集合U,输出此边。更新closedge[]的值,选择集合V-U中点到k和u之间较小的哪个权值存到clodedge数组中。重复此步骤,直到所有的顶点都加入u中。

用邻接矩阵存储图,用一维数组存储现已有的树到其他定点的最小权值,用另一个一维数组存储某个点是否在生成树中。

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>

using namespace std;

#define Maxn 110
#define INF 9999999
int maz[Maxn][Maxn],lowcase[Maxn],flag[Maxn];
//maz[i][j]表示i到j的距离,注意无向图和重边!lowcase数组存的是现已在树里的点所能到达的点(Maxn)的最小权值
//flag数组是用来标记某个点(Maxn)是否已经在树里面
int prim(int n)
{
    int i,j,ans = 0,pos,mi;
    memset(flag,0,sizeof(flag));//起初所有点都不在生成树中
    for (i = 2; i <= n; ++i)
        lowcase[i] = maz[1][i];//先以1作为根节点,更新lowcase数组
    lowcase[1] = 0;//为了数组里的值全(自己到自己的距离是0)
    flag[1] = 1;//1这个点(初始点)标记为已在树里面
    for (i = 0; i < n-1; ++i)//循环n-1次,每次找一个点纳入到树里面,加上1根节点总共就是n个点
    {
        mi = INF;//mi为每次在lowcase数组里找到的最小值,所以刚开始赋值成最大值
        for (j = 1; j <= n; ++j)//寻找最小权值的点
        {
            if (!flag[j] && lowcase[j] < mi)//j点不在树里面并且权值小
            {
                mi = lowcase[j];
                pos = j;//记录一下这个将要进入生成树的点
            }
        }
        ans += mi;//记录最小生成树的总权值
        flag[pos] = 1;//将此次寻找的点标记为已经加入生成树
        for (j = 1; j <= n; ++j)//用新的节点更新lowcase数组
        {
            if (!flag[j] && maz[pos][j] < lowcase[j])//判断新加入的点到其他所有未加入的点的距离是否比前一个点的小
            {
                lowcase[j] = maz[pos][j];//如果小的话更新数组的值
            }
        }
    }
    return ans;//返回最小生成树的总权值
}
int main()
{
    int n,i,j;
    while (~scanf("%d",&n) && n)//顶点个数
    {
        for (i = 1; i <= n; ++i)
        {
            for (j = 1; j <= n; ++j)
                maz[i][j] = i == j ? 0 : INF;//用邻接矩阵存储图
        }//刚开始得把数组里的数存成无穷大//本身到本身的距离是0//点和点之间的距离是无穷大
        int a,b,c;
        for (i = 0; i < n*(n-1)/2; ++i)//最大边数
        {
            scanf("%d%d%d",&a,&b,&c);
            if (c < maz[a][b])
                maz[a][b] = maz[b][a] = c;//无向图+重边
        }
        int ans = prim(n);//n个点的最小生成树的总长度
        printf("%d\n",ans);
    }
    return 0;
}

算法二:克鲁斯卡尔(加边法)

将所有边的权值排序。

1)初始状态看为只有顶点没有边,每一个顶点看作一个连通分量。

2)选择最小权值的边,如果该边连接了不同连通分量,则将该边加入集合T,否则舍去该边,继续寻找下一条权值最小的边。

3)重复2)直到所有顶点都在同一个连通分量中。

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>

using namespace std;

    #define Maxn 1100
    int p[Maxn];
    int find(int x)
    {
        return p[x] == x ? x : p[x] = find(p[x]);
    }//并查集
    struct node
    {
        int u,v,w;
    };//每条边的情况,u,v是边的端点,w是边的权值
    struct node q[Maxn*500];  //定义边的个数
    int cmp(node a,node b)
    {
        return a.w < b.w;
    }//sort将边按权值排序
    int main()
    {
        int n,m,sum,num,i,x,y;
        while (~scanf("%d",&n) && n)
        {
            for (i = 1; i <= n; ++i)
                p[i] = i;//初始化每个顶点是一个连通分量
            m = n * (n-1) / 2;  //最大边的数
            for (i = 0; i < n*(n-1)/2; ++i)
            {
                scanf("%d%d%d",&q[i].u,&q[i].v,&q[i].w);//****不需要考虑重边的情况,因为重边的存在并不覆盖
                //之前的边,重边参与排序,选出重边中最小的,就算遍历到了重边中较大的,此时端点已经在同
                //一棵树中了,所以重边的存在不会有影响
            }
            sort(q,q+m,cmp);//将边按照权值排序
            sum = num = 0;
            for (i = 0; i < m; ++i)//m条边,从其中选出****n-1条边,然后跳出循环
            {
                x = find(q[i].u);
                y = find(q[i].v); //判断两个顶点的边是否在同一个连通分量中
                if (x != y)  //不在同一个连通分量中
                {
                    if (x > y)
                        p[x] = y;
                    else
                        p[y] = x;//连通分量标志合并到哪个较小的中去
                    sum += q[i].w; //记录生成树的总权值
                    ++num; //记录加入生成树中的边数
                }
                if (num == n-1)  //当足够了n-1条边的时候停止
                    break;
            }
            printf("%d\n",sum);  //输出总权值
        }
        return 0;
    }




  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值