最小生成树

(克鲁斯卡尔算法) 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)的更多相关文章

  1. POJ1251 Jungle Roads (最小生成树&Kruskal&Prim)题解

    题意: 输入n,然后接下来有n-1行表示边的加边的权值情况.如A 2 B 12 I 25 表示A有两个邻点,B和I,A-B权值是12,A-I权值是25.求连接这棵树的最小权值. 思路: 一开始是在做莫 ...

  2. 最小生成树之 prim算法和kruskal算法(以 hdu 1863为例)

    最小生成树的性质 MST性质:设G = (V,E)是连通带权图,U是V的真子集.如果(u,v)∈E,且u∈U,v∈V-U,且在所有这样的边中, (u,v)的权c[u][v]最小,那么一定存在G的一棵最 ...

  3. 最小生成树算法prim and kruskal

    一.最小生成树定义:  从不同顶点出发或搜索次序不同,可得到不同的生成树  生成树的权:对连通网络来说,边附上权,生成树也带权,我们把生成树各边的权值总和称为生成树的权  最小代价生成树:在一个连通网 ...

  4. C++编程练习(10)----“图的最小生成树“(Prim算法、Kruskal算法)

    1.Prim 算法 以某顶点为起点,逐步找各顶点上最小权值的边来构建最小生成树. 2.Kruskal 算法 直接寻找最小权值的边来构建最小生成树. 比较: Kruskal 算法主要是针对边来展开,边数 ...

  5. java实现最小生成树的prim算法和kruskal算法

    在边赋权图中,权值总和最小的生成树称为最小生成树.构造最小生成树有两种算法,分别是prim算法和kruskal算法.在边赋权图中,如下图所示: 在上述赋权图中,可以看到图的顶点编号和顶点之间邻接边的权 ...

  6. 无向带权图的最小生成树算法——Prim及Kruskal算法思路

    边赋以权值的图称为网或带权图,带权图的生成树也是带权的,生成树T各边的权值总和称为该树的权. 最小生成树(MST):权值最小的生成树. 生成树和最小生成树的应用:要连通n个城市需要n-1条边线路.可以 ...

  7. 最小生成树(prim和kruskal)

    最小生成树(prim和kruskal) 最小生成树的最优子结构性质 设一个最小生成树是T.如果选出一个T中的一条边,分裂成的两个树T1,T2依然是它们的点集组成的最小生成树.这可以用反证法来证.反着来 ...

  8. 数据结构(三十三)最小生成树(Prim、Kruskal)

    一.最小生成树的定义 一个连通图的生成树是一个极小的连通子图,它含有图中全部的顶点,但只有足以构成一棵树的n-1条边. 在一个网的所有生成树中,权值总和最小的生成树称为最小代价生成树(Minimum ...

  9. 最小生成树——Kruskal与Prim算法

    最小生成树——Kruskal与Prim算法 序: 首先: 啥是最小生成树??? 咳咳... 如图: 在一个有n个点的无向连通图中,选取n-1条边使得这个图变成一棵树.这就叫“生成树”.(如下图) 每个 ...

  10. MST最小生成树及Prim普鲁姆算法

    MST在前面学习了Kruskal算法,还有一种算法叫做Prim的.这两者的区别是Prim算法适合稠密图,比如说鸟巢这种几乎所有点都有相连的图.其时间复杂度为O(n^2),其时间复杂度与边的数目无关:而 ...

随机推荐

  1. 硬件管理平台 - 公共项目搭建(Nancy部分)

    项目变更 之前使用的是Nancy库进行项目搭建的,使用的Nuget版本及其他引用如下 <?xml version="1.0" encoding="utf-8&quo ...

  2. 从零玩转系列之微信支付实战PC端项目构建+页面基础搭建 | 技术创作特训营第一期

    一.前言 欢迎来到本期的博客!在这篇文章中,我们将带您深入了解前端开发领域中的一个热门话题: 如何使用 Vue 3 和 Vite 构建前端项目.随着现代 Web 应用程序的需求不断演进, 选择适当的工 ...

  3. 手写raft(二) 实现日志复制

    1. Raft日志复制介绍 在上一篇博客中MyRaft实现了leader选举,为接下来实现日志复制功能打下了基础: 手写raft(一) 实现leader选举 日志复制是raft最核心也是最复杂的功能, ...

  4. Python 潮流周刊#16:优雅重要么?如何写出 Pythonic 的代码?

    你好,我是猫哥.这里每周分享优质的 Python.AI 及通用技术内容,大部分为英文.标题取自其中两则分享,不代表全部内容都是该主题,特此声明. 本周刊由 Python猫 出品,精心筛选国内外的 25 ...

  5. 6、Spring之基于xml的自动装配

    6.1.场景模拟 6.1.1.创建UserDao接口及实现类 package org.rain.spring.dao; /** * @author liaojy * @date 2023/8/5 - ...

  6. ATtiny88初体验(三):串口

    ATtiny88初体验(三):串口 ATtiny88单片机不包含串口模块,因此只能使用软件方式模拟串口时序. 串口通信时序通常由起始位.数据位.校验位和停止位四个部分组成,常见的配置为1位起始位.8位 ...

  7. C++算法之旅、05 基础篇 | 第二章 数据结构

    常用代码模板2--数据结构 - AcWing 笔试用数组模拟而不是结构体 使用结构体指针,new Node() 非常慢,创建10万个节点就超时了,做笔试题不会用这种方式(优化是提前初始化好数组,但这样 ...

  8. 原来你是这样的SpringBoot--Async异步任务

    本节我们一起学习一下SpringBoot中的异步调用,主要用于优化耗时较长的操作,提高系统性能和吞吐量. 一.新建项目,启动异步调用 首先给启动类增加注解@EnableAsync,支持异步调用 @En ...

  9. 熟练掌握并充分利用CSS3的新特性,更新完毕。

    1.1  尝试新颖的CSS3特性 首先,我们来看一个具体的案例.  https://code.juejin.cn/pen/7277536985772720139   1.2  CSS3新特性简介和浏览 ...

  10. 在Go中如何实现并发

    Go语言的并发机制是其强大和流行的一个关键特性之一.Go使用协程(goroutines)和通道(channels)来实现并发编程,这使得编写高效且可维护的并发代码变得相对容易.下面是Go的并发机制的详 ...