题目:
计算带权无向连通图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;
}