1. 程式人生 > >題解 luogu P3366 【【模板】最小生成樹】

題解 luogu P3366 【【模板】最小生成樹】

最小生成樹kruskal演算法!

最弱紅名的首道圖論題

貪心演算法,按邊的權值排序,然後看當前指定的兩點有木有已經在一棵樹上,如果有,不管,沒有,merge。然後ans加上那條邊的權值。

#include<bits/stdc++.h>
using namespace std;
struct path
{
	int k,l,q;
}p[200000];
int bcj[200000];
int get(int x)
{
	if (bcj[x]==x)return x;
	else return bcj[x]=get(bcj[x]);
}
void merge(int x,int y)
{
	bcj[get(x)]=get(y);
}//標準的並查集get和merge
void haha(int l,int r)
{
    int i,j,x,y,n;
    x=p[(l+r)/2].q;i=l;j=r;
    do{
    while(p[i].q<x)i++;
    while(p[j].q>x)j--;
    if (i<=j)
    {swap(p[i].q,p[j].q);swap(p[i].k,p[j].k);swap(p[i].l,p[j].l);i++;j--;}
    }while(i<=j);
    if (i<r)haha(i,r);
    if (j>l)haha(l,j);
}//快排
int main()
{
	int i,j,x,y,n,ans=0;
	cin>>x>>y;
    for (i=1;i<=x;i++)bcj[i]=i;//初始化並查集
	for (i=1;i<=y;i++)
	{
		int k,l;
		cin>>p[i].k>>p[i].l>>p[i].q;
	}//讀入邊
	haha(1,y);
	for (i=1;i<=y;i++)
		if (get(p[i].k)!=get(p[i].l)){merge(p[i].k,p[i].l);ans+=p[i].q;};//如果不在同樹上就合併
	for (i=1;i<=x;i++)
	{
		if (get(i)!=get(1)){cout<<"orz";return 0;}
	}//如果有多個樹根,輸出orz
	cout<<ans;
	return 0;
}

the end