1.生成树:将图删去一些边变成树。假设图中有n个点m条边,那么需要删除m-(n-1)条边。
2.最小生成树:只生成树中权值和最小的树。(针对有权图,无向图)
3.最小生成算法有两种,Kruskal算法必须掌握。
3.1 Prim算法:其算法复杂度为O(),其算法思想与Dijkstra算法类似:
第一步:选最小;
第二步:标记;
第三步:更新;
Prim算法和Dijkstra算法的区别在于d[i]的含义不同:在Dijkstra算法中,的[i]表示起点到i号点的最短路径;在Prim算法中,d[i]表示与第i个节点相连的边的最短长度(没有被别人占过)
3.2 Kruskal算法:其算法复杂度为O(n log n),其算法核心思想是一次加边其核心技术是排序(按边的权值大小排序)与并查集(判断是否构成环)。
4.实例
#include <bits/stdc++.h>
using namespace std;
struct Edge
{
int u,v,w;
Edge(int u1,int v1,int w1): u(u1), v(v1), w(w1) {}//结构体初始化函数
Edge(){}
};
Edge e[200005];
int father[5005];
int find(int i)//查找i的父亲 ,查
{
if(father[i] == i)//若果i的父亲是i ,说明i是根节点
{
return i;
}
else//否则查找i的父亲的父亲
{
father[i]=find(father[i]);//查找i的父亲的父亲
return father[i];
}
}
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;//初始化时,i的父亲是他自己
}
for(int i=0;i<M;i++)
{
int X,Y,Z;
cin>>X>>Y>>Z;//边的起点,终点,和权值
e[i]=Edge(X,Y,Z);//边集
}
sort(e,e+M,comp);//按照权值从小到大进行排序
int k=0,tot=0;
for(int i=0;i<M;i++)//Kruskal
{
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++;//边数加1
}
if(k==N-1) //如果边数为n-1
{
break;//提前结束
}
}
cout<<tot<<endl;//输出最小生成树的权值
return 0;
}