最小生成树
例题: 洛谷3366
题目描述
如题,给出一个无向图,求出最小生成树,如果该图不连通,则输出orz
输入格式
第一行包含两个整数N、M,表示该图共有N个结点和M条无向边。(N<=5000,M<=200000)
接下来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
Kruskal O(nlogn)
//https://www.luogu.org/problem/P3366
#include<cmath>
#include<bits/stdc++.h>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<string>
using namespace std;
#define LL int
int read()
{
int x=0,w=1;
char ch=0;
while(ch<'0'||ch>'9')
{
if(ch=='-')
w=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
x=x*10+ch-'0';
ch=getchar();
}
return w*x;
}
int n,m,cnt,tt;
struct node{
int x,y,z;
};
node edge[200005];
void add(int a,int b,int w)
{
edge[++cnt].x=a;
edge[cnt].y=b;
edge[cnt].z=w;
}
bool cmp(node a,node b)
{
return a.z<b.z;
}
int fa[5005];
int found(int x)
{
int pre;
int r=x;
while(fa[r]!=r)
{
r=fa[r];
}
while(x!=r)
{
pre=fa[x];
fa[x]=r;
x=pre;
}
return x;
}
bool ifin(int a,int b)
{
return found(a)==found(b);
}
void un(int a,int b)
{
int aa=found(a);
int bb=found(b);
fa[aa]=bb;
}
int ans,aa,bb,cc;
int main()
{
n=read();
m=read();
for(register int i=1;i<=n;i++)//并查集初始化
{
fa[i]=i;
}
for(register int i=1;i<=m;i++)
{
aa=read();
bb=read();
cc=read();
add(aa,bb,cc);
}
sort(edge+1,edge+cnt+1,cmp);//按照边从小到大排序
for(register int i=1;i<=cnt;i++)
{
if(tt==n-1)//tt记录已经在树中的边的个数 如果等于n-1说明建树完毕
break ;
if(!ifin(edge[i].x,edge[i].y))//如果该边连接的两点不在同一集合中 则合并
{
ans+=edge[i].z;
un(edge[i].x,edge[i].y);
tt++;
}
}
if(tt<n-1)//判断是否成功建树
{
cout<<"orz"<<endl;
}
else
{
cout<<ans<<endl;
}
return 0;
}
朴素Prim O(n^2)
懒得写了 下次再说2333