最小生成树(Kruskal Prim)
最小生成树
(克鲁斯卡尔算法) Kruskal
给定一个n个点m条边的无向图,图中可能存在重边和自环,边权可能为负数。
求最小生成树的树边权重之和,如果最小生成树不存在则输出impossible。
给定一张边带权的无向图 \(G=(V, E)\),其中\(V\)表示图中点的集合,\(E\)表示图中边的集合,\(n=|V|\),\(m=|E|\)。
由\(V\)中的全部\(n\)个顶点和\(E\)中\(n-1\)条边构成的无向连通子图被称为G的一棵生成树,其中边的权值之和最小的生成树被称为无向图G的最小生成树。
输入格式
第一行包含两个整数n和m。
接下来m行,每行包含三个整数\(u,v,w\),表示点u和点v之间存在一条权值为w的边。
输出格式
共一行,若存在最小生成树,则输出一个整数,表示最小生成树的树边权重之和,如果最小生成树不存在则输出impossible。
数据范围
\(1 \leq n \leq 10^5\)
\(1 \leq m \leq 2∗10^5\)
图中涉及边的边权的绝对值均不超过1000。
输入样例:
4 5
1 2 1
1 3 2
1 4 3
2 3 2
3 4 4
输出样例:
6
思路:
\(Kruskal\)主要用于稀疏图, 用邻接矩阵来处理,时间复杂度为\(O(mlogn)\)。按照边的权重顺序(从小到大)将边加入生成树中,但是若加入该边会与生成树形成环则不加入该边。直到树中含有\(V-1\)条边为止。这些边组成的就是该图的最小生成树。
来自维基百科 原作者:Schulllz
其中如果生成树如果与将要加入的边生成环则说明\((a,b)\)同祖先, 比如上图那种情况, 因此我们这里就可以使用并查集来判断,如果不会生成环中, 则a != b
一定会成立。
代码:
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 100010, M = 200010, INF = 0X3f3f3f3f;
int n, m;
int p[N];
struct Edge
{
int a, b, w;
bool operator< (const Edge &W)const //重载运算符
{
return w < W.w;
}
}edges[M];
int find(int x)
{
if(p[x] != x) p[x] = find(p[x]);
return p[x];
}
int kruskal()
{
sort(edges, edges + m);
for(int i = 1; i <= n; i++) p[i] = i;
int res = 0, cnt = 0;
for(int i = 0; i < m; i++)
{
int a = edges[i].a, b = edges[i].b, w = edges[i].w;
a = find(a), b = find(b);
if(a != b)
{
p[a] = b;
res += w;
cnt++;
}
}
if(cnt < n-1) return INF; //找不到n-1条边肯定有的不连通
return res;
}
int main()
{
scanf("%d%d", &n, &m);
for(int i = 0; i < m; i++)
{
int a, b, w;
scanf("%d%d%d", &a, &b, &w);
edges[i] = {a, b, w};
}
int t = kruskal();
if(t == INF) puts("impossible");
else printf("%d\n", t);
return 0;
}
(普利姆算法) Prim
给定一个n个点m条边的无向图,图中可能存在重边和自环,边权可能为负数。
求最小生成树的树边权重之和,如果最小生成树不存在则输出impossible。
给定一张边带权的无向图\(G=(V, E)\),其中\(V\)表示图中点的集合,\(E\)表示图中边的集合,\(n=|V|,m=|E|\)。
由\(V\)中的全部\(n\)个顶点和\(E\)中\(n-1\)条边构成的无向连通子图被称为\(G\)的一棵生成树,其中边的权值之和最小的生成树被称为无向图\(G\)的最小生成树。
输入格式
第一行包含两个整数\(n\)和\(m\)。
接下来\(m\)行,每行包含三个整数\(u,v,w\)表示点\(u\)和点\(v\)之间存在一条权值为\(w\)的边。
输出格式
共一行,若存在最小生成树,则输出一个整数,表示最小生成树的树边权重之和,如果最小生成树不存在则输出impossible。
数据范围
\(1 \leq n \leq 500\)
\(1 \leq m \leq 10^5\)
图中涉及边的边权的绝对值均不超过10000。
输入样例:
4 5
1 2 1
1 3 2
1 4 3
2 3 2
3 4 4
输出样例:
6
思路
\(Prim\)主要用于稠密图, 用邻接表来处理,时间复杂度为\(O(n^2)\)
void Prim()
{
dist[i] = +∞
for (int i = 0; i < n; i++)
{
1.t<-集合外距离最近的点
st[t] = true //标记
2.用t更新其他点到集合的距离
}
}
代码
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 510, INF = 0x3f3f3f3f;
int n, m;
int g[N][N];
int dist[N]; //当前点到集合的距离
bool st[N];
int prim()
{
memset(dist, 0x3f, sizeof dist);
int res = 0;
for(int i = 0; i < n; i++)
{
int t = -1;
for(int j = 1; j <= n; j++) //寻找距离集合最近的点
{
if(!st[j] && (t == -1 || dist[t] > dist[j]))
{
t = j;
}
}
if(i && dist[t] == INF) return INF; //说明不存在最小生成树 由V中的全部n个顶点和E中n-1条边构成的无向连通子图被称为G的一棵生成树,
if(i) res += dist[t]; //一定要记得先累加 不然如果存在自环的话更新后再累加会出问题
st[t] = true;
for(int j = 1; j <= n; j++) dist[j] = min(dist[j], g[t][j]); //更新
}
return res;
}
int main()
{
scanf("%d%d", &n, &m);
memset(g, 0x3f, sizeof g);
while(m--)
{
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
g[a][b] = g[b][a] = min(g[a][b], c);
}
int t = prim();
if(t == INF) puts("impossible");
else printf("%d\n", t);
return 0;
}
最小生成树(Kruskal Prim)的更多相关文章
- POJ1251 Jungle Roads (最小生成树&Kruskal&Prim)题解
题意: 输入n,然后接下来有n-1行表示边的加边的权值情况.如A 2 B 12 I 25 表示A有两个邻点,B和I,A-B权值是12,A-I权值是25.求连接这棵树的最小权值. 思路: 一开始是在做莫 ...
- 最小生成树之 prim算法和kruskal算法(以 hdu 1863为例)
最小生成树的性质 MST性质:设G = (V,E)是连通带权图,U是V的真子集.如果(u,v)∈E,且u∈U,v∈V-U,且在所有这样的边中, (u,v)的权c[u][v]最小,那么一定存在G的一棵最 ...
- 最小生成树算法prim and kruskal
一.最小生成树定义: 从不同顶点出发或搜索次序不同,可得到不同的生成树 生成树的权:对连通网络来说,边附上权,生成树也带权,我们把生成树各边的权值总和称为生成树的权 最小代价生成树:在一个连通网 ...
- C++编程练习(10)----“图的最小生成树“(Prim算法、Kruskal算法)
1.Prim 算法 以某顶点为起点,逐步找各顶点上最小权值的边来构建最小生成树. 2.Kruskal 算法 直接寻找最小权值的边来构建最小生成树. 比较: Kruskal 算法主要是针对边来展开,边数 ...
- java实现最小生成树的prim算法和kruskal算法
在边赋权图中,权值总和最小的生成树称为最小生成树.构造最小生成树有两种算法,分别是prim算法和kruskal算法.在边赋权图中,如下图所示: 在上述赋权图中,可以看到图的顶点编号和顶点之间邻接边的权 ...
- 无向带权图的最小生成树算法——Prim及Kruskal算法思路
边赋以权值的图称为网或带权图,带权图的生成树也是带权的,生成树T各边的权值总和称为该树的权. 最小生成树(MST):权值最小的生成树. 生成树和最小生成树的应用:要连通n个城市需要n-1条边线路.可以 ...
- 最小生成树(prim和kruskal)
最小生成树(prim和kruskal) 最小生成树的最优子结构性质 设一个最小生成树是T.如果选出一个T中的一条边,分裂成的两个树T1,T2依然是它们的点集组成的最小生成树.这可以用反证法来证.反着来 ...
- 数据结构(三十三)最小生成树(Prim、Kruskal)
一.最小生成树的定义 一个连通图的生成树是一个极小的连通子图,它含有图中全部的顶点,但只有足以构成一棵树的n-1条边. 在一个网的所有生成树中,权值总和最小的生成树称为最小代价生成树(Minimum ...
- 最小生成树——Kruskal与Prim算法
最小生成树——Kruskal与Prim算法 序: 首先: 啥是最小生成树??? 咳咳... 如图: 在一个有n个点的无向连通图中,选取n-1条边使得这个图变成一棵树.这就叫“生成树”.(如下图) 每个 ...
- MST最小生成树及Prim普鲁姆算法
MST在前面学习了Kruskal算法,还有一种算法叫做Prim的.这两者的区别是Prim算法适合稠密图,比如说鸟巢这种几乎所有点都有相连的图.其时间复杂度为O(n^2),其时间复杂度与边的数目无关:而 ...
随机推荐
- 类WPF跨平台模仿TIM
类WPF跨平台模仿TIM Avalonia是什么? Avalonia 是一个功能强大的框架,使开发人员能够使用 .NET 创建跨平台应用程序.它使用自己的渲染引擎来绘制UI控件,确保在各种平台上保持一 ...
- 关于"覆盖问题”的反思
[HAOI2007]覆盖问题 题目描述 某人在山上种了N棵小树苗.冬天来了,温度急速下降,小树苗脆弱得不堪一击,于是树主人想用一些塑料薄膜把这些小树遮盖起来,经过一番长久的思考,他决定 用3个L*L的 ...
- 关于No changes detected
查看app在settings.py文件夹中是否有注册.
- 基于inotify-tools和rsync实现文件实时同步
前言 系统:centos 7 inotify-tools版本:3.14(3.22版本测试有问题,所以找的比较旧的一版) 主机IP: 192.168.137.7(服务端,接收同步文件) 192.168. ...
- QTreeView自绘实现酷炫样式
本篇文章结合笔者的经历,介绍一种通过重写QTreeView绘制事件,使用QPainter来实现好看的列表的方式. 导语 Hi,各位读者朋友,大家好.相信大家在日常的工作中,经常会接触到QTreeVie ...
- Linux虚拟机报错Job for network.service failed because the control process exited with error codeLinux虚拟机报错的解决方法
发布于 2 天前 3 次阅读 Linux虚拟机设置静态ip后,突然发现联网连不上了,ssh也无法使用,重启network后仍旧无法使用.按照网络上的方法发现没有效果后,右键如下位置将nat模式转换为 ...
- do_fork(一)
fork 是linux创建进程的系统调用,相关的函数(不只是系统调用)还有 vfork,clone,sys_frok等.这些函数会整理不同参数,再调用到 do_fork 中. 本篇文章主要介绍do_f ...
- 论文精读:带有源标签自适应的半监督域适应(Semi-Supervised Domain Adaptation with Source Label Adaptation)
Semi-Supervised Domain Adaptation with Source Label Adaptation 具有源标签适应的半监督域适应 原文链接 Abstract 文章指出当前的半 ...
- Hutool,一个超好用的 Java 工具类库
一.简介 Hutool是一个小而全的Java工具类库,通过静态方法封装,降低相关API的学习成本,提高工作效率,使Java拥有函数式语言般的优雅,让Java语言也可以"甜甜的". ...
- 【matplotlib基础】--样式表
Matplotlib库 由于诞生的比较早,所以其默认的显示样式很难符合现在的审美,这也是它经常为人诟病的地方. 不过,经过版本更迭之后,现在 Matplotlib 已经内置了很多样式表,通过使用不同的 ...