【algo&ds】8.最小生成树
1.最小生成树介绍
什么是最小生成树?
最小生成树(Minimum spanning tree,MST)是在一个给定的无向图G(V,E)中求一棵树T,使得这棵树拥有图G中的所有顶点,且所有边都是来自图G中的边,并且满足整棵树的边权值和最小。
2.prim算法
和Dijkstra算法很像!!请看如下Gif图,prim算法的核心思想是对图G(V,E)设置集合S,存放已被访问的顶点,然后每次从集合V-S中选择与集合S的最短距离最小的一个顶点(记为u),访问并加入集合S。之后,令顶点u为中间点,优化所有从u能到达的顶点v与集合s之间的最短距离。这样的操作执行n次,直到集合s中包含所有顶点。

不同的是,Dijkstra算法中的dist是从源点s到顶点w的最短路径;而prim算法中的dist是从集合S到顶点w的最短路径,以下是他们的伪码描述对比,关于Dijkstra算法的详细描述请参考文章

算法实现:
#include<iostream>
#include<vector>
#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<Vertex> MST; // 最小生成树
// 初始化图信息
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; // 初始化图
dist[i] = INF; // 初始化距离
parent[i] = -1; // 初始化并查集
}
// 初始化点
for(int i=0;i<Ne;i++){
cin>>v1>>v2>>w;
G[v1][v2] = w;
G[v2][v1] = w;
}
}
// Prim算法前的初始化
void IniPrim(Vertex s){
dist[s] = 0;
MST.push_back(s);
for(Vertex i =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(Vertex i=1;i<=Nv;i++)
if(dist[i] && dist[i] < min){
min = dist[i];
xb = i;
}
return xb;
}
void output(){
cout<<"被收录顺序:"<<endl;
for(Vertex i=1;i<=Nv;i++)
cout<<MST[i]<<" ";
cout<<"权重和为:"<<sum<<endl;
cout<<"该生成树为:"<<endl;
for(Vertex i=1;i<=Nv;i++)
cout<<parent[i]<<" ";
}
void Prim(Vertex s){
IniPrim(s);
while(1){
Vertex v = FindMin();
if(v == -1)
break;
sum += dist[v];
dist[v] = 0;
MST.push_back(v);
for(Vertex w=1;w<=Nv;w++)
if(G[v][w] && dist[w])
if(G[v][w] < dist[w]){
dist[w] = G[v][w];
parent[w] = v;
}
}
}
int main(){
build();
Prim(1);
output();
return 0;
}
关于prim算法的更加详细讲解请参考视频
3.kruskal算法
Kruskal算法也可以用来解决最小生成树的问题,其算法思想很容易理解,典型的边贪心,其算法思想为:
- 在初始状态时隐去图中所有的边,这样图中每个顶点都是一个单独的连通块,一共有n个连通块
- 对所有边按边权从小到大进行排序
- 按边权从小到大测试所有边,如果当前测试边所连接的两个顶点不在同一个连通块中,则把这条测试边加入当前最小生成树中,否则,将边舍弃。
- 重复执行上一步骤,直到最小生成树中的边数等于总顶点数减一 或者测试完所有边时结束;如果结束时,最小生成树的边数小于总顶点数减一,说明该图不连通。
请看下面的Gif图!

算法实现:
#include<iostream>
#include<string>
#include<vector>
#include<queue>
#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<Node> MST; // 最小生成树
priority_queue<Node> 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<Ne;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<<"被收录顺序:"<<endl;
for(Vertex i=0;i<Nv;i++)
cout<<MST[i].weight<<" ";
cout<<"权重和为:"<<sum<<endl;
for(Vertex i=1;i<=Nv;i++)
cout<<parent[i]<<" ";
cout<<endl;
}
int main(){
build();
Kruskal();
output();
return 0;
}
关于kruskal算法更详细的讲解请参考视频
【algo&ds】8.最小生成树的更多相关文章
- 【algo&ds】4.B树、字典树、红黑树、跳表
上一节内容[algo&ds]4.树和二叉树.完全二叉树.满二叉树.二叉查找树.平衡二叉树.堆.哈夫曼树.散列表 7.B树 B树的应用可以参考另外一篇文章 8.字典树Trie Trie 树,也叫 ...
- DS图--最小生成树
题目描述 根据输入创建无向网.分别用Prim算法和Kruskal算法构建最小生成树.(假设:输入数据的最小生成树唯一.) 输入 顶点数n n个顶点 边数m m条边信息,格式为:顶点1 顶点2 权值 P ...
- 【algo&ds】2.线性表
1.线性表 线性表(英语:Linear List)是由n(n≥0)个数据元素(结点)a[0],a[1],a[2]-,a[n-1]组成的有限序列. 其中: 数据元素的个数n定义为表的长度 = " ...
- 【algo&ds】【吐血整理】4.树和二叉树、完全二叉树、满二叉树、二叉查找树、平衡二叉树、堆、哈夫曼树、B树、字典树、红黑树、跳表、散列表
本博客内容耗时4天整理,如果需要转载,请注明出处,谢谢. 1.树 1.1树的定义 在计算机科学中,树(英语:tree)是一种抽象数据类型(ADT)或是实作这种抽象数据类型的数据结构,用来模拟具有树状结 ...
- 【algo&ds】3.栈和队列
1.堆栈 堆栈(Stack):具有一定操作约束的线性表(只在一端(栈顶,Top)做插入.删除) 先进后出特性 1.1堆栈的抽象数据类型描述 类型名称: 堆栈(Stack) 数据对象集:一个有0个或多个 ...
- 【algo&ds】1.时间复杂度和空间复杂度分析
1.时间复杂度分析O(f(n)) 分析方法 只关注循环执行次数最多的一段代码 加法原则 乘法原则 高优先级原则 常见时间复杂度量级 多项式量级和非多项式量级.其中,非多项式量级只有两个:O(2^n) ...
- 【algo&ds】0.数据结构和算法入门
解决问题方法的效率,跟数据的组织方式有关 解决问题方法的效率,跟空间的利用效率有关 解决问题方法的效率,跟算法的巧妙程度有关 什么是数据结构 数据对象在计算机中的组织方式 逻辑结构 物理存储结构 数据 ...
- 【algo&ds】7.最短路径问题
单源最短路径问题:从某固定源点出发,求其到所有其他顶点的最短路径 (有向)无权图:BFS (有向)有权图:Dijkstra算法 多源最短路径问题:求任意两顶点间的最短路径 直接将单源最短路算法调用|V ...
- 【algo&ds】9.拓扑排序、AOV&AOE、关键路径问题
对一个有向无环图(Directed Acyclic Graph简称DAG)G进行拓扑排序,是将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若边<u,v>∈E(G),则u在线性 ...
随机推荐
- 使用css实现导航下方线条随导航移动效果
HTML部分 <ul> <li><a href="">第一条</a></li> <li><a href ...
- 10.Linux用户权限
1.权限基本概述 1. 什么是权限? 我们可以把它理解为操作系统对用户能够执行的功能所设立的限制,主要用于约束用户能对系统所做的操作,以及内容访问的范围,或者说,权限是指某个特定的用户具有特定的系统资 ...
- Cassandra官方介绍及安装
Cassandra官方介绍及安装 这个数据库有很高的伸缩性和可用性,你完全不需要向性能妥协.在硬件或者云设施上做修改 官网:Cassandra官网 一.简介 cassandra这个数据库有很高的伸缩性 ...
- vue 开发插件流程
UI demo UI 插件汇总 我的github iSAM2016 在练习写UI组件的,用到全局的插件,网上看了些资料.看到些的挺好的,我也顺便总结一下写插件的流程: 声明插件-> 写插件-&g ...
- Linux常用命令及示例(全)
NO 分类 PS1 命令名 用法及参数 功能注解1 显示目录信息 # ls ls -a 列出当前目录下的所有文件,包括以.头的隐含文件 # ls ls -l或ll 列出当前目录下文件的详细信息 # l ...
- MyBatis(2)-- MyBatis配置mybatis-config.xml
一.properties属性 1.可以在mybatis-config.xml中使用property子元素配置 <properties resource="jdbc.properties ...
- Redis(一)Redis基础
一.Redis是什么 Redis是一种基于键值对(key-value)的NoSQL数据库,与很多键值对数据库不同的是,Redis中的值可以是由string(字符串).hash(哈希).list(列表) ...
- Bigo的Java面试,我挂在了第三轮技术面上.........
背景 前段时间家里出了点事,辞职回家待了一段时间,处理完老家的事情后就回到广州这边继续找工作,大概是国庆前几天我去面试了一家叫做Bigo(YY的子公司),面试的职位是面向3-5年的Java开发,最终自 ...
- 并发中如何保证缓存DB双写一致性(JAVA栗子)
并发场景中大部分处理的是先更新DB,再(删缓.更新)缓存的处理方式,但是在实际场景中有可能DB更新成功了,但是缓存设置失败了,就造成了缓存与DB数据不一致的问题,下面就以实际情况说下怎么解决此类问题. ...
- SQL语句实现:当A列大于B列时选择A列否则选择B列,当B列大于C列时选择B列否则选择C列
分享一道今天的面试题:SQL语句实现:数据库中有A B C三列,当A列大于B列时选择A列否则选择B列,当B列大于C列时选择B列否则选择C列 第一种:使用case when...then...else ...