18448 最小生成树

Description
给定结点数为n,边数为m的带权无向连通图G,所有结点编号为1,2,3…n。
求图G的最小生成树的边权和。

输入格式
第一行两个正整数n和m。n,m<=2000
之后的m行,每行三个正整数a,b,w,描述一条连接结点a和b,边权为w的边。1=<a,b<=n,w<=10^18。
注意可能存在重边和自环。

输出格式
一个整数表示图G的最小生成树的边权和(注意用长整型)。

输入样例
7 12
1 2 9
1 5 2
1 6 3
2 3 5
2 6 7
3 4 6
3 7 3
4 5 6
4 7 2
5 6 3
5 7 6
6 7 1

输出样例
16

最小生成树构造算法主要为:普里姆 ( Prim ) 算法 或 克鲁斯卡尔( Kruskal )算法

一、普里姆 ( Prim ) 算法

代码:

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

int n, m;//顶点数、边数
long long Map[2005][2005] = { 0 };//邻接矩阵
long long val[2005] = { 0 };//记录当前顶点所连边的最小权值的数组
int v[2005] = { 0 };//标记数组

long long prime()
{
    //先把第一个顶点加入到最小生成树中
    v[1] = 1;//标记第一个顶点已经加入到最小生成树中
    int i, j;
    for (i = 1; i <= n; i++)//遍历加入到生成树中的第一个顶点,将其所连的较小权值更新进val数组
        if (v[i] == 0 && Map[1][i] < val[i])//如果有更小的权值,则更新到最小权值数组中
            val[i] = Map[1][i];

    long long sum = 0;
    for (i = 1; i < n; i++)//将剩下的n-1个顶点加入到最小生成树中
    {
        long long Min = 1e18;
        int index = 1;
        //获取当前权值数组中的最小权值及其顶点下标
        for (j = 1; j <= n; j++)
        {
            if (v[j] == 0 && val[j] < Min)//如果当前顶点仍未加入到最小生成树中,则查找最小权值
            {
                Min = val[j];//更新最小权值,以便下次比较查找
                index = j;//记录 与 已经加到最小生成树中的顶点 相连的 最小权值的顶点的下标
            }
        }

        v[index] = 1;//将 与 已经加到最小生成树中的顶点 相连的 最小权值的顶点 加入到最小生成树中
        sum += val[index];//累加最小权值
//        cout << index << ' ' << val[index] << endl;//输出本次选的顶点和权值

        //因为将新的顶点加入到最小生成树当中,所以需要更新当前状态下,最小权值数组
        for (j = 1; j <= n; j++)
        {
            //如果当前顶点仍未加入到最小生成树中,并且刚加入的顶点与 未加入进来的所有顶点所连的边中,有更小的权值,则更新到全债数组中
            if (v[j] == 0 && Map[index][j] < val[j])
                val[j] = Map[index][j];
        }
    }
    return sum;
}

int main()
{
    memset(Map, 127 / 3, sizeof(Map));//初始化Map的权值为较大值
    memset(val, 127 / 3, sizeof(val));//初始化记录当前顶点所连边的最小权值数组值为较大值
    cin >> n >> m;
    int i;
    int a, b;
    long long w;
    for (i = 1; i <= m; i++)
    {
        cin >> a >> b >> w;
        if (a == b)//解决自环
            continue;
        Map[a][b] = Map[b][a] = min(Map[a][b], w);//解决重边
    }
    cout << prime() << endl;
    return 0;
}
  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值