最小生成树----Kruskal
Kruskal与Prim不同的是Prim是以任意一个点为起点,一次向其他点遍历,而Kruskal则是以边为起点,向其他边遍历,Kruskal的时间复杂度远远小于Prim。
思路:
- 先将所有的边排序
- 依次找出边权最小的边,并查集判断他是否以连接
- 如果未连接,则将其连接,并继续找剩下的最小的边
- 直到边数为(n-1)
时间复杂度O(nlogn)
Code
#include<iostream>
#include<memory.h>//memset的头文件
#include<algorithm>//快速排序的头文件
using namespace std;
const int N=2e5+5;
int ans;
int n,m;//顶点数与边数
int fa[N];//并查集的父域
struct edge{
int u,v;//边的起点与终点
int cost;//边的权值
}e[N];
bool cmp(edge a,edge b)//结构体比较大小的函数
{
return a.cost<b.cost;
}
void init(int n)//并查集初始化
{
for(int i=1;i<=n;i++)
fa[i]=i;
return ;
}
int find(int x)//并查集函数
{
if(fa[x]==x)
return x;
else
{
fa[x]=find(fa[x]);
return fa[x];
}
}
int kruskal(int n,int m)
{
int e_n=0;//已经建立的边数
init(n);//初始化
sort(e,e+m,cmp);//排序
for(int i=1;i<=m-1;i++)
{
int fau=find(e[i].u);//边的起点的父域
int fav=find(e[i].v);//边的终点的父域
if(fau!=fav)//如果两个父域不同,则证明他们两个点未连接
{
fa[fau]=fav;//讲两个点连接起来
ans+=e[i].cost;//讲边权累加
//cout<<e[i].cost<<' ';
e_n++;//边数加1
if(e_n==n-1) break; //如果边数到达了n-1,则退出循环
}
}
if(e_n!=n-1) return -1;//判断是否构成一颗生成树
else return 1;
}
int main()
{
cin>>n>>m;
for(int i=1;i<=m;i++)
e[i].cost=9999;//给每条边初始化最大值
for(int i=1;i<=m;i++)
{
int w;
cin>>e[i].u>>e[i].v>>w;
e[i].cost=min(w,e[i].cost);//防止有重复输入的数据,取最小的
}
if(kruskal(n,m)==-1) cout<<"orz"<<endl;
else cout<<ans<<endl;
return 0;
}
京公网安备 11010502036488号