1. 程式人生 > >C++ P3366 【模板】最小生成樹 --- kruskal

C++ P3366 【模板】最小生成樹 --- kruskal

 Kruskal的用處:

  • 得出一個圖的一個最小生成樹(最小生成樹就是一個圖中總權值最小的一個子樹)

Kruskal的思想:

  • 由於要獲得最小生成樹,而最小生成樹一定連線了所有結點,所以邊權最小的邊一定會被選擇(這個需要自己證明
  • 然後,我們將邊權最小的邊進行縮點,縮點的方法是使用並查集,也就是把互相連線的點放到同一個集合。
  • 然後重複第一個步驟。當已選擇的邊的數量等於點的總數減一時,則最小生成樹已建立完成。

Kruskal的具體實現:

  • 獲取邊權最小的邊可以使用sort函式,也可以使用優先佇列
  • 縮點可以使用並查集

例題:

https://www.luogu.org/problemnew/show/P3366

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
int ans=0,cnt=0,n,m,fa[200005];
struct Edge{
	int u,v,w;
}e[200005];
int cmp(Edge a,Edge b){
	return a.w<b.w;
}
void addEdge(int u,int v,int w){
	e[++cnt].u=u;
	e[cnt].v=v;
	e[cnt].w=w;
}
int find(int a){
	while(a!=fa[a]){
		a=fa[a]=fa[fa[a]];
	}
	return a;
}
void kruskal(){
	int eu,ev;
	int sum=0;
	for(int i=1;i<=m;i++){
		eu=find(e[i].u),ev=find(e[i].v);
		if(eu==ev)continue;
		sum++;
		fa[eu]=ev;
		ans+=e[i].w;
		if(sum==n-1)return;
	}
}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++){
		fa[i]=i;
	}
	for(int i=1;i<=m;i++){
		int a,b,c;
		scanf("%d%d%d",&a,&b,&c);
		addEdge(a,b,c);
	}
	sort(e,e+m,cmp);
	kruskal();
	printf("%d\n",ans);
	return 0;
}

 


歡迎加入我們的OI討論群

群號:849352599