1. 生成树:将图删去一些边变成树。假定图有n个点,m条边,那么需要删掉m-(n-1)条边。
2. 最小生成树:指生成树中权值之和最小的树。
3. 最小生成树算法有两种:(Kruskal算法必须掌握)
a. Prim算法:其算法复杂度为O(n*n),其算法思想与Dijkstra算法类似,第一步选最小,第二部标记,第三步更新。Prim算法和Dijkistra算法的区别在于的 d [ i ] 的含义不同:在Dijkistra算法中,含义是从起点到第i个点的长度,在Prim算法中,含义是与第i个结点相连的边的最短长度(没有被别人提前占用)。
b. Kruskal算法:其算法复杂度为O(nlogn),其算法核心思想是依次加边法,其核心技术排序(quick sort,按边的权值进行排序)和并查集(判断是否构成环)
4. 实例
5. 代码:
#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) {}
Edge() {}
};
Edge e[200005];
int father[5005];//并查集,父亲表示法,父亲相同表示他们在同一集合
//并查集的查找函数
int Find(int x)//查找x的父亲
{
if(father[x]==x)//找到根节点
{
return x;
}
else
{
father[x]=Find(father[x]);//递归,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;//n点数,m边数
cin>>n>>m;
//并查集初始化
for(int i=0; i<n; i++)
{
father[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;
//Kruskal算法
for(int i=0; i<m; i++)//依次加边法
{
if(Find(e[i].u)!=Find(e[i].v))//判断第i条边的起点和终点是否在同一个集合里
{
father[Find(e[i].u)]=Find(e[i].v);//如果不在一个集合就合并在一起
tot+=e[i].w;//将第i条边加到最小生成树中
k++;//边数增1
}
if(k==n-1)
{
break;//最小生成树的边数找够了,提前结束
}
}
cout<<tot;
return 0;
}
/*
6 8
0 1 1
0 2 5
0 3 2
1 2 3
1 4 7
2 5 6
3 5 8
4 5 4
*/