最小生成树

(克鲁斯卡尔算法) 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. Django: 获取头信息

    如何获取请求头信息 使用如下函数request.META.get("HTTP_请求头函数"),需要注意的是,请求头变量需要全部大写. 其他注意事项如下所示: 如果headerkey ...

  2. pandas 根据内容匹配并获取索引

    bool = ExcelDataStr.str.contains("Item No./Customer/Saler") # 初始位置:initial position, 终位置:e ...

  3. RocketMq消费原理及源码解析

    消费原理概览 先简单说下常见的rocketMq的部署方式,上图中broker为真正计算和存储消息的地方,而nameServer负责维护broker地 图中右侧consume message部分即是本文 ...

  4. 学习OI两年我到底收获了什么

    做一个小小的总结 学习了两年的代码,刚刚要进入高中,留下一点文字给以前的学习做一个总结. 命中注定の邂逅-- 这两年之间,和编程产生了比学习更为低调的羁绊关系(我觉得用这个词语比较合适).编程给我带来 ...

  5. 重返照片的原始世界:我为.NET打造的RAW照片解析利器

    重返照片的原始世界:我为.NET打造的RAW照片解析利器 如果你是我的老读者,你可能还记得,在2019年,我冒险进入了一片神秘的领域--用C#解析RAW格式的照片: 20191208 - 用.NET解 ...

  6. 《Kali渗透基础》10. 提权、后渗透

    @ 目录 1:提权 2:Admin 提权为 System 2.1:at 2.2:sc 2.3:SysInternal Suite 2.4:进程注入提权 3:抓包嗅探 4:键盘记录 5:本地缓存密码 5 ...

  7. Docker 镜像库国内加速的几种方法

    概述 在国内,拉取 Docker 镜像速度慢/时不时断线/无账号导致限流等,比较痛苦. 这里提供加速/优化的几种方法. 梳理一下,会碰到以下情况: 国内下载速度慢/时不时断线:是因为网络被限制了. 没 ...

  8. HTML网页/KRPano项目一键打包EXE工具(HTML网页打包成单个windows可执行文件exe)

    HTML一键打包EXE工具使用说明 工具简介 HTML一键打包EXE工具(HTML封装EXE,桌件)能把任意HTML项目(网址)一键打包为单个EXE文件,可以脱离浏览器和服务器,直接双击即可运行.支持 ...

  9. Solution -「POJ 1322」Chocolate

    Description Link. 包里有无穷多个巧克力,巧克力有 \(c\) 种颜色,每次从包里拿出不同颜色巧克力的概率都是相等的,桌面的巧克力不允许颜色相同,若某次拿出的巧克力与桌上的巧克力颜色相 ...

  10. Solution -「GXOI / GZOI 2019」AND OR Sum

    Description Link. 给定一个 \(N \times N\) 的矩阵,她希望求出: 该矩阵的所有子矩阵的 \(\texttt{AND}\) 值之和(所有子矩阵 \(\texttt{AND ...