在最小生成树的问题中,我们常常不必把生成树表示出来,一般是计算生成树权值之和等问题
Kruskal算法就是把所有边排序一下,从小到大将边放到生成树当中,但是要满足将边放入后不形成环的条件。
两个要点:
1. 要先将所有的边进行排序
2. 利用并查集来快速判断两个点是否在同一颗树当中,如果在的话,边放入必然会产生环
利用Kruskal算法计算最小生成树的权值总和
注意:这个问题我们不需要把图建立出来
#include <iostream>
#include <algorithm>
using namespace std;
int parent[1005]; //并查集的实现数组,开的大小为点的个数
int find(int p)
{
if( p!=parent[p] ) parent[p]=find( parent[p] );
return parent[p];
}
struct node{ //node为边,参数为边连着的两个点和权值,开的大小为边的个数
int x;
int y;
int v;
bool operator<(const node &n) const
{
return v<n.v;
}
}p[100005];
int main()
{
int n,m,ans = 0;
cin >> n >> m;
for( int i = 1 ; i <=n ; i++ )
{
parent[i] = i; //一开始每一个点都是一棵树
}
for( int i = 0 ; i < m ; i++ )
{
cin >> p[i].x >> p[i].y >> p[i].v;
}
sort(p,p+m); //将边进行排序
for( int i = 0 ; i < m ; i++ )
{
int rootx = find(p[i].x);
int rooty = find(p[i].y);
if( rootx != rooty ) //如果这两个点不在同一棵树上
{
parent[rootx] = rooty; //把一颗树连到另一颗树上
ans += p[i].v;
n--; //树的个数减少1
}
if( n==1 ) break; //如果只剩下一颗树了,break出去
}
cout << ans << endl;
return 0;
}
时间开销主要在对边的排序上,所以时间复杂度为Elog(E),E为图的边数