离散数学 习题篇 —— 最小生成树

题目:

计算带权无向连通图G的最小生成树。

输入格式:

第一行两个整数:N(1≤N≤300000),表示结点集;表示边的条数。
接下来M行,每行表示一条带权的边,用3个整数u,v,c表示,分别表示一条边的两个端点以及其权值(权值范围0≤c≤109)。

输出格式:

一个整数,表示G的最小生成树的边权之和。

输入样例:

5 10
1 2 3
1 3 7
1 4 9
1 5 5
2 3 6
2 4 8
2 5 4
3 4 9
3 5 7
4 5 2

输出样例:

15

题解:

那么只看题目的话,应该也能知道这个题是最小生成树吧

啥是最小生成树呢?

翻翻课本吧兄弟,直接讲实现方式。

首先,给边排个序。通过权值来排,从小到大。

然后,遍历这个序列,把这个序列里没用过的边用上,直到所有的点都连起来,就ojbk了。

那么在用边的时候,要注意不能出现环,有环的话就不是树了不是?而这里,就要用到传说中的最美丽的数据结构……之一!并查集了。至于并查集是啥,咋用,可以看这篇文章:
数据结构基础——并查集
(是的我还没有写,等写了就把链接贴出来)

代码:

#include <bits/stdc++.h>
using namespace std;
//虽然叫Node但是这个结构体表示的是边和它的权值
struct Node
{
	int u, v;
	int c;
};
//一会排序的时候会用到的函数
bool cmp(Node a, Node b)
{
	return a.c < b.c;
}
//存边的数组,一会的时候要排序遍历
vector<Node> G;

//实现并查集的东东
vector<int> f; //判断i和j是不是在一个集合用的数组
//查找元素k所在的集合
int find(int k)
{
	return f[k] == k ? k : f[k] = find(f[k]);
}
//把x所在的集合和y所在的集合并起来
int unite(int x, int y)
{
	int t1 = find(x);
	int t2 = find(y);
	if(t1 != t2)
	{
		f[t1] = t2;
		return true;
	}
	return false;
}

//从这里看是好习惯哦
int main(int argc, char const *argv[])
{
	//输入用的巴拉巴拉,懂了吧
	int n, k;
	cin >> n >> k;
	//把数组开好
	f.resize(n + 3);
	//这个函数用来初始化数组,具体等我并查集那个文章吧
	iota(f.begin(), f.end(), 0);
	//输入边和权值了
	while(k--)
	{
		int u, v, c;
		cin >> u >> v >> c;
		G.push_back({u, v, c});
	}
	//按照cmp这个函数定义的排序方式排个序
	sort(G.begin(), G.end(), cmp);
	//数有点大,开个long long
	long long sum = 0;
	//遍历每个边,要是加进去成环的话,这个边是放不进并查集的
	for(auto i : G)
	{
		if(unite(i.u, i.v))
			sum += i.c;
	}
	cout << sum;
	return 0;
}
  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值