1.生成树:就是将图删掉一些边,变成树,假定图有n个点,其生成树一定是n-1条边
2.最小生成树:就是指生成树中权值最小的树之和
3.最小生成树算法有两种(Kruskal算法必须掌握)
a.prim算法:其算法复杂度为O(n*n),其算法思想与Dijkstra算法类似,算法共分三步:1.选最小 2.标记 3.更新。(他们的区别是d[i]的定义不同)在Dijkstra算法中d[i]表示从起点到第i个结点最短路径的长度。在prim算法中与i结点相连的最短的边(除去被别的点抢先占用的边)
b.Kruskal算法:其算法复杂度O(n*logn),其算法核心是排序和并查集,需要重点掌握
4.实例:
#include<bits/stdc++.h>
using namespace std;
struct Edge
{
int u, v, w;
Edge(int _u, int _v, int _w):u(_u), v(_v), w(_w)//初始化时u v w 值确定
{
}
Edge()//初始化函数2,初始化时u v w 值不确定
{
}
};
Edge e[200005];
//并查集
int father[5005];
int find(int x)//并查集的查找函数
{
if(father[x]==x)
{
return x;
}
else
{
father[x]=find(father[x]);//递归调用,有路径压缩的并查集
return father [x];
}
}
//排序的比较规则
bool comp(const Edge &a,const Edge &b)
{
if(a.w <b.w)//按边的权值从小到大排序
{
return true;
}
return false;
}
int main ()
{
int N,M;
cin>>N>>M;
for(int i=1;i<=N;i++)
{
father[i]=i;//并查集,父亲表示法
}
for(int i=0;i<M;i++)
{
int u,v,w;
cin>>u>>v>>w;
e[i]=Edge(u,v,w);
}
sort(e,e+M,comp);//排序
int k=0;//边的计数器
int tot=0;//边的权值的累加器
for(int i=0;i<M;i++)//依次处理i条边
{
if(find(e[i].u) != find(e[i].v))//如果u和v不在同一个集合里
{
father[find(e[i].u)]=find(e[i].v);
tot += e[i].w;//累加权值
k++;//边数增一
}
if(k == N-1)
{
break;
}
}
cout<<tot;
return 0;
}
/*
6
9
1 2 1
1 6 2
2 3 4
2 6 4
3 4 2
3 6 1
4 5 3
4 6 3
5 6 5
*/