Bootstrap

洛谷 P3366 【模板】最小生成树

题目描述

如题,给出一个无向图,求出最小生成树,如果该图不连通,则输出 orz

输入格式

第一行包含两个整数 N,M,表示该图共有 N 个结点和 M 条无向边。

接下来 M 行每行包含三个整数 Xi​,Yi​,Zi​,表示有一条长度为 Zi​ 的无向边连接结点 Xi​,Yi​。

输出格式

如果该图连通,则输出一个整数表示最小生成树的各边的长度之和。如果该图不连通则输出 orz

输入输出样例

输入 #1

4 5
1 2 2
1 3 2
1 4 3
2 3 4
3 4 3

输出 #1

7
说明/提示

数据规模:

  • 对于 20% 的数据,N≤5,M≤20。
  • 对于 40% 的数据,N≤50,M≤2500。
  • 对于 70% 的数据,N≤500,M≤1e4。
  • 对于 100% 的数据:1≤N≤5000,1≤M≤2×1e5,1≤Zi​≤1e4。
样例解释

所以最小生成树的总边权为 2+2+3=7。

思路:

并查集+贪心

代码如下:
 

#include<iostream>
#include<algorithm>
using namespace std;
const int N = 2e5+10;
int n,m;
struct Edge{
	int u,v,w;
}e[N];
int fa[N];
bool compare(const Edge &a,const Edge &b)
{
	return a.w < b.w;
}
int find(int i)
{
	if(fa[i] != i)
	{
		fa[i] = find(fa[i]);
	}
	return fa[i];
}
bool check(int u,int v)
{
	int root_u = find(u);
	int root_v = find(v);
	return root_v == root_u;
}
void set(int u,int v)
{
	int root_u = find(u);
	int root_v = find(v);
	if(root_u != root_v)
	{
		fa[root_v] = root_u;
	}
}
int MST()
{
	int sum = 0,cnt = 0;
	sort(e + 1,e + 1 + m,compare);
	for(int i = 1 ; i <= n ; i++)
	fa[i] = i;
	for(int i = 1 ; i <= m ; i++)
	{
		int u = e[i].u;
		int v = e[i].v;
		int w = e[i].w;
		if(!check(u,v))
		{
			set(u,v);//连接
			sum += w;
			cnt++;	
		}
	}
	if(cnt < n -1)
	return -1;
	else
	return sum;
}
int main(void)
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	 
	cin >> n >> m;
	for(int i = 1 ; i <= m ; i++)
	{
		cin >> e[i].u >> e[i].v >> e[i].w;
	}
	int ans = MST();
	if(ans == -1)
	cout << "orz";
	else
	cout << ans; 
	return 0;
}

;