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算法求最小生成树

在包含n个顶点的联通图中,找出只有(n-1)条边包含所有n个顶点的连通子图。

代码如下:(Prim算法)

#include <iostream>
#include <vector>
#include <cstring>
#include <limits.h>
using namespace std;

long long n,m,i,j,k,x,y,z;
struct node
{
    long long adj;//顶点
    long long value;//边上的权值
};
vector<node> e[100000];
long long d[100000],v[100000];
/**< 返回相邻边最小的权值 */
long long getmin()
{
    long long minv=LLONG_MAX,mini,i;//i可不能省
    for(i=1;i<=n;i++)//题设:所有结点编号为1,2,3...n
    {
        if(v[i]==0&&d[i]<minv)
        {
            minv=d[i];//找到了最小权值
            mini=i;//最小边的一个顶点
        }
    }
    return mini;
}
void prim()
{
    memset(d,127,sizeof(d));//初始化最大值
    d[1]=0;
    long long sum=0;
    for(i=0;i<n;i++)//n次循环结束,则所有的顶点也遍历到了
    {
        long long t=getmin();
        v[t]=1;//标记
        sum+=d[t];//记录相邻边的最小权值
        for(j=0;j<e[t].size();j++)//相邻顶点
        {
            long long adj=e[t][j].adj,value=e[t][j].value;
            if(value<d[adj])
                d[adj]=value;//相当于把相邻顶点权值放进d数组中
        }
    }
    cout<<sum;
}
int main()
{
    ios::sync_with_stdio(false);
    memset(v,0,sizeof(v));//对比较大的数组进行初始化,此时初始化标记数组
    cin>>n>>m;
    for(i=0;i<m;i++)
    {
        cin>>x>>y>>z;
        e[x].push_back({y,z});
        e[y].push_back({x,z});//无向
    }
    prim();
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值