最小生成树算法总结(Kruskal,Prim)
今天复习最小生成树算法。
最小生成树指的是在一个图中选择n-1条边将所有n个顶点连起来,且n-1条边的权值之和最小。形象一点说就是找出一条路线遍历完所有点,不能形成回路且总路程最短。
Kurskal算法
kurskal算法的核心思想是将边按权值排序,每次选出权值最小的边,只要不会形成回路就加入结果集,如果形成了回路就不选这条边,类似于贪心的思想。
具体做法是先将边按权值升序排序然后依次遍历,判断是否形成回路的方法是将点划分不同集合,初始状态每个点为一个集合,只有当一条边的两端分别位于两个集合时才选择这条边,否则就丢弃,这里用到了并查集来处理集合关系,可以参考这篇博文:https://www.cnblogs.com/czc1999/p/11823820.html,选择一条边之后要将两个点合并到同一集合。
模板题: https://www.luogu.com.cn/problem/P3366
代码如下,还是比较好理解的,时间复杂度为\(O(MlogM)\)。
#include <iostream>
#include <algorithm>
using namespace std;
int n, m;
int pre[5005];
int Find(int x) { return pre[x] == x ? pre[x] : pre[x] = Find(pre[x]); }
struct line
{
int from, to, val;
bool operator<(line a) { return val < a.val; }
}Arr[200005];
int Kruskal()
{
sort(Arr, Arr + m);
int cnt = n, res = 0;
for (int i = 0; i < m && cnt > 1; i++)
{
int x = Find(Arr[i].from), y = Find(Arr[i].to);
if (x != y)//x和y不在一个集合
{
pre[x] = y;//合并两个集合
cnt--;//找到了一条边
res += Arr[i].val;
}
}
return cnt == 1 ? res : -1;//如果cnt不等于1说明没找到n-1条边,无最小生成树
}
int main() {
cin >> n >> m;
for (int i = 0; i < n; i++)pre[i] = i;
for (int i = 0; i < m; i++)cin >> Arr[i].from >> Arr[i].to >> Arr[i].val;
int res = Kruskal();
if (-1 == res)cout << "orz"; else cout << res;
return 0;
}
prim算法
Kruskal算法是选择边的思路,而prim算法通过选择点来得到最小生成树,有点类似于Dijkstra的感觉,初始源点可以任意选择,把点划分成已选择的点和未选择的点两个集合,需要维护一个dis数组代表每个点到已选择点的最短距离,不断把dis最小的未选择点加入已选择点集合然后更新dis,当所有点都变成已选择点(dis==0)的时候就得到了最小生成树。
代码如下,真的是跟Dijkstra很像了。
#include <iostream>
#include <algorithm>
using namespace std;
#define inf 2000000000
int n, m;
int dis[5005];
int total = 0;
int head[5005], val[400005], to[400005], nextL[400005];
void AddLine(int a, int b, int c)
{
total++;
to[total] = b;
val[total] = c;
nextL[total] = head[a];
head[a] = total;
}
int Prim()
{
int res = 0;
for (int i = 2; i <= n; i++)dis[i] = inf;
for (int i = 0; i < n; i++)//循环n次找n个点
{
int Min = inf, u = 1;
for (int j = 1; j <= n; j++)//找下一个最近的未选择点
{
if (dis[j] != 0 && dis[j] < Min)
{
Min = dis[j]; u = j;
}
}
if (Min == inf && u != 1)return -1;//如果遍历之后未选择点dis都为inf,说明该图是非连通图
res += dis[u];
dis[u] = 0;
for (int j = head[u]; j; j = nextL[j])//更新该点周围的dis
{
if (dis[to[j]] > val[j])dis[to[j]] = val[j];
}
}
return res;
}
int main() {
cin >> n >> m;
int a, b, c;
for (int i = 0; i < m; i++)
{
cin >> a >> b >> c;
AddLine(a, b, c);
AddLine(b, a, c);
}
int res = Prim();
if (-1 == res)cout << "orz"; else cout << res;
return 0;
}
堆优化
既然prim也是要每次取dis最小的点,当然也和Dijkstra一样可以用堆优化,朴素的prim时间复杂度为\(O(n^2)\),优化后达到\(O(nlogn)\),代码如下:
#include <iostream>
#include <algorithm>
#include <queue>
using namespace std;
#define inf 2000000000
int n, m;
int dis[5005];
int total = 0;
int head[5005], val[400005], to[400005], nextL[400005];
bool mark[5005];
void AddLine(int a, int b, int c)
{
total++;
to[total] = b;
val[total] = c;
nextL[total] = head[a];
head[a] = total;
}
typedef pair<int, int> p;
priority_queue<p, vector<p>, greater<p>> q;
int Prim()
{
int res = 0;
for (int i = 2; i <= n; i++)dis[i] = inf;
q.push(p(0, 1));
while (!q.empty())
{
int u=q.top().second,v=q.top().first;
q.pop();
if (mark[u])continue;
mark[u] = true;
dis[u] = 0;
res += v;
for (int i = head[u]; i ; i=nextL[i])
{
if (dis[to[i]] > val[i])
{
dis[to[i]] = val[i];
q.push(p(val[i], to[i]));
}
}
}
return res;
}
int main() {
cin >> n >> m;
int a, b, c;
for (int i = 0; i < m; i++)
{
cin >> a >> b >> c;
AddLine(a, b, c);
AddLine(b, a, c);
}
int res = Prim();
if (-1 == res)cout << "orz"; else cout << res;
return 0;
}
所以选择使用哪个算法就看是点多还是边多了。
最小生成树算法总结(Kruskal,Prim)的更多相关文章
- 最小生成树模板【kruskal & prim】
CDOJ 1966 Kruskal 解法 时间复杂度O(mlogm) m为边数,这里主要是边排序占时间,后面并查集还好 #include <cstdio> #include <cst ...
- 图-最小生成树算法之Kruskal及其Java实现
1.Kruskal算法 Kruskal算法基于贪心,因此它追求的是近似最优解,也就是说由Kruskal得出的生成树并不一定是最优解. Kruskal算法求最小生成树的关键在于,每次选取图中权值最小(及 ...
- 最小生成树--Prim算法,基于优先队列的Prim算法,Kruskal算法,Boruvka算法,“等价类”UnionFind
最小支撑树树--Prim算法,基于优先队列的Prim算法,Kruskal算法,Boruvka算法,“等价类”UnionFind 最小支撑树树 前几节中介绍的算法都是针对无权图的,本节将介绍带权图的最小 ...
- 最小生成树算法(Prim,Kruskal)
边赋以权值的图称为网或带权图,带权图的生成树也是带权的,生成树T各边的权值总和称为该树的权. 最小生成树(MST):权值最小的生成树. 生成树和最小生成树的应用:要连通n个城市需要n-1条边线路.可以 ...
- C++编程练习(10)----“图的最小生成树“(Prim算法、Kruskal算法)
1.Prim 算法 以某顶点为起点,逐步找各顶点上最小权值的边来构建最小生成树. 2.Kruskal 算法 直接寻找最小权值的边来构建最小生成树. 比较: Kruskal 算法主要是针对边来展开,边数 ...
- [数据结构]最小生成树算法Prim和Kruskal算法
最小生成树 在含有n个顶点的连通图中选择n-1条边,构成一棵极小连通子图,并使该连通子图中n-1条边上权值之和达到最小,则称其为连通网的最小生成树. 例如,对于如上图G4所示的连通网可以有多棵权值总 ...
- 无向带权图的最小生成树算法——Prim及Kruskal算法思路
边赋以权值的图称为网或带权图,带权图的生成树也是带权的,生成树T各边的权值总和称为该树的权. 最小生成树(MST):权值最小的生成树. 生成树和最小生成树的应用:要连通n个城市需要n-1条边线路.可以 ...
- 最小生成树-Prim算法与Kruskal算法
一.最小生成树(MST) ①.生成树的代价:设G=(V,E)是一个无向连通网,生成树上各边的权值之和称为该生成树的代价. ②.最小生成树:在图G所有生成树中,代价最小的生成树称为最小生成树. 最小生成 ...
- 最小生成树算法详解(prim+kruskal)
最小生成树概念: 一个有 n 个结点的连通图的生成树是原图的极小连通子图,且包含原图中的所有 n 个结点,并且有保持图连通的最少的边. 最小生成树可以用kruskal(克鲁斯卡尔)算法或prim(普里 ...
随机推荐
- PT教程 - 应用系列 - ECO修复Timing(理论+实践+脚本分享)
本文转自:自己的微信公众号<集成电路设计及EDA教程> <PT教程 - 应用系列 - ECO修复Timing(理论+实践+脚本分享)> 这篇推文讲一下数字IC设计中的post ...
- 死磕mysql(3)
花了一个晚上得出的结论,autocommit=1是不是立刻提交,autocommit=0是没有写入数据库的关闭数据,除非遇到commit和rollback........把自己给逗了关闭数据库发现数据 ...
- 二、通过工厂方法来配置bean
调用静态工厂方法创建 Bean是将对象创建的过程封装到静态方法中. 当客户端需要对象时, 只需要简单地调用静态方法, 而不同关心创建对象的细节. 要声明通过静态方法创建的 Bean, 需要在 Bean ...
- GORM CRUD指南
CRUD通常指数据库的增删改查操作,本文详细介绍了如何使用GORM实现创建.查询.更新和删除操作. CRUD CRUD通常指数据库的增删改查操作,本文详细介绍了如何使用GORM实现创建.查询.更新和删 ...
- android studio闪退的原因
可能是因为某个监听的问题,比如没有把Mainacticity中定义的button和布局文件中的按钮控件关联起来,就会出现这个问题
- 一口气说出Redis 5种数据结构及对应使用场景,面试要加分的
整理了一些Java方面的架构.面试资料(微服务.集群.分布式.中间件等),有需要的小伙伴可以关注公众号[程序员内点事],无套路自行领取 更多优选 一口气说出 9种 分布式ID生成方式,面试官有点懵了 ...
- 小白学 Python 数据分析(5):Pandas (四)基础操作(1)查看数据
在家为国家做贡献太无聊,不如跟我一起学点 Python 人生苦短,我用 Python 前文传送门: 小白学 Python 数据分析(1):数据分析基础 小白学 Python 数据分析(2):Panda ...
- 手机控制电脑第二弹之HIPC
点击蓝字关注我们 是否很多时候电脑不在身边,又急需要使用,比如正好要用一个文件,又没有放在我们的网盘中,想用手机查看电脑状态,但是很多太复杂的方式不会使用,需要简单的方式,今天方成分享给你 前言 故事 ...
- 动手学习Pytorch(6)--卷积神经网络基础
卷积神经网络基础 本节我们介绍卷积神经网络的基础概念,主要是卷积层和池化层,并解释填充.步幅.输入通道和输出通道的含义. 二维卷积层 本节介绍的是最常见的二维卷积层,常用于处理图像数据. 二维 ...
- CSS选择器世界
CSS选择器世界 CSS选择器的分类与优先级 css选择器分为四类:选择器.选择符(后代关系的空格.>.+.~.||).伪类.伪元素(::before.::after.::first-lette ...