1 .最小生成树介绍
最小生成树是什么?
最小生成树(Minimum spanning tree,MST )在某无向图g(v,e )中求树t,该树拥有图g的所有顶点,所有边都来自图g的边,树整体边的权重
2.prim算法
类似于Dijkstra算法! 请看下面的Gif图。 prim算法的核心思想是在图g(v,e )中设置集合s,存储被访问的顶点,每次从集合V-S中选出一个与集合s的最短距离最小的顶点),访问加入集合s。 之后,以顶点u为中间点,将从u可以到达的所有顶点v和集合s的最短距离进行最优化。 这样的操作执行n次直到集合s中包含所有顶点。
不同之处在于,Dijkstra算法的dist是从源点s到顶点w的最短路径; 另一方面,prim算法的dist是从集合s到顶点w的最短路径,以下是他们的伪码描述的对比。 有关Dijkstra算法的详细描述,请参见文章
算法实现: #include
#包含
#define INF 100000
#define MaxVertex 105
typedef int Vertex;
int G[MaxVertex][MaxVertex];
int parent[MaxVertex]; //并列调查
int dist[MaxVertex]; //距离
int Nv; //节点
int Ne; //边
int sum; //权重和
using namespace std;
vector MST //最小生成树
//初始化映射信息
void build () }
Vertex v1、v2;
int w;
cinNvNe;
for(intI=1; i=Nv; I ) {
for(intj=1; j=Nv; j )
G[i][j]=0; //初始化映射
dist[i]=INF; //初始化距离
parent[i]=-1; //初始化并检查
}
//初始化点
for(intI=0; I
cinv1v2w;
G[v1][v2]=w;
G[v2][v1]=w;
}
}
//Prim算法前的初始化
voidiniprim(Vertexs ) {
dist[s]=0;
MST.push_back(s );
for(vertexI=1; i=Nv; I )
if(g(s ) ) I ) {
dist[i]=G[s][i];
parent[i]=s;
}
}
//在未收录中寻找dist最小的点
Vertex FindMin () }
int min=INF;
Vertex xb=-1;
for(vertexI=1; i=Nv; I )
if(dist[I]dist[I]min ) {
min=dist[i];
xb=i;
}
返回XB;
}
void输出
出局了
for(vertexI=1; i=Nv; I )
出局了
出局了
出局了
for(vertexI=1; i=Nv; I )
出局了
}
voidprim(Vertexs ) {
iniprim(s;
wile(1) {
Vertex v=FindMin (;
if(v==-1 ) ) )。
布雷克;
sum =dist[v];
dist[v]=0;
MST.push_back(v );
for(vertexw=1; w=Nv; w )
if(g ) v ) w ) dist ) w ) )
if(g(v ) ) w ) dist ) w ) {
dist[w]=G[v][w];
parent[w]=v;
}
}
}
I
nt main(){build();
Prim(1);
output();
return 0;
}
关于prim算法的更加详细讲解请参考视频 https://www.bilibili.com/video/av55114968?p=99
3.kruskal算法
Kruskal算法也可以用来解决最小生成树的问题,其算法思想很容易理解,典型的边贪心,其算法思想为:
● 在初始状态时隐去图中所有的边,这样图中每个顶点都是一个单独的连通块,一共有n个连通块
● 对所有边按边权从小到大进行排序
● 按边权从小到大测试所有边,如果当前测试边所连接的两个顶点不在同一个连通块中,则把这条测试边加入当前最小生成树中,否则,将边舍弃。
● 重复执行上一步骤,直到最小生成树中的边数等于总顶点数减一 或者测试完所有边时结束;如果结束时,最小生成树的边数小于总顶点数减一,说明该图不连通。
请看下面的Gif图!
算法实现:#include
#include
#include
#include
#define INF 100000
#define MaxVertex 105
typedef int Vertex;
int G[MaxVertex][MaxVertex];
int parent[MaxVertex]; // 并查集最小生成树
int Nv; // 结点
int Ne; // 边
int sum; // 权重和
using namespace std;
struct Node{
Vertex v1;
Vertex v2;
int weight; // 权重
// 重载运算符成最大堆
bool operator < (const Node &a) const
{
return weight>a.weight;
}
};
vector MST; // 最小生成树
priority_queue q; // 最小堆
// 初始化图信息
void build(){
Vertex v1,v2;
int w;
cin>>Nv>>Ne;
for(int i=1;i<=Nv;i++){
for(int j=1;j<=Nv;j++)
G[i][j] = 0; // 初始化图
parent[i] = -1;
}
// 初始化点
for(int i=0;i
cin>>v1>>v2>>w;
struct Node tmpE;
tmpE.v1 = v1;
tmpE.v2 = v2;
tmpE.weight = w;
q.push(tmpE);
}
}
// 路径压缩查找
int Find(int x){
if(parent[x] < 0)
return x;
else
return parent[x] = Find(parent[x]);
}
// 按秩归并
void Union(int x1,int x2){
if(parent[x1] < parent[x2]){
parent[x1] += parent[x2];
parent[x2] = x1;
}else{
parent[x2] += parent[x1];
parent[x1] = x2;
}
}
void Kruskal(){
// 最小生成树的边不到 Nv-1 条且还有边
while(MST.size()!= Nv-1 && !q.empty()){
Node E = q.top(); // 从最小堆取出一条权重最小的边
q.pop(); // 出队这条边
if(Find(E.v1) != Find(E.v2)){ // 检测两条边是否在同一集合
sum += E.weight;
Union(E.v1,E.v2); // 并起来
MST.push_back(E);
}
}
}
void output(){
cout<
for(Vertex i=0;i
cout<
cout<
for(Vertex i=1;i<=Nv;i++)
cout<
cout<
}
int main(){
build();
Kruskal();
output();
return 0;
}
关于kruskal算法更详细的讲解请参考视频 https://www.bilibili.com/video/av55114968?p=100
推荐课程:C语言教程