标签:int Kruskal 查集 859 算法 连接 dis
一、Kruskal算法
⭐️ 1、基本思路:
(1) 将所有边按权重从小到大排序
(2) 枚举每条边 \(a \sim b\) ,权重是\(c\)
if \(a\),\(b\)不在一个集合中 :
将这条边加入集合中
结束
⭐️ 2、克鲁斯卡尔算法的基本思想是以边为主导地位,普利姆算法是以点为主导的地位的。
⭐️ 3、prim算法适合稠密图,kruskal算法适合稀疏图。
理由也挺简单的,Kruskal是按边存的,边少就合适,边多就不适合。稀疏图当然边少,稠密图是点少,但边多,边可能达到节点数的平方,即每个节点都与其它节点有边。
模拟一下:
假如有以下几个城市,之间都有相连的道路:
根据kruskal的原理,我们需要对边权dis进行排序,每次找出最小的边。
排序后,最小的边自然是第8条边,于是4和6相连。
遍历继续,第二小的边是1号,1和2联通。
再后来是边3连接1,4。
dis也是14的还有边5,它连接3,4。
其次是dis为15的边4,但是2和4已经相连了,pass。
然后是dis为16的两条边(边2和边9),边2连接1和3,边9连接3和6,它们都已经间接相连,pass。
再然后就是dis为22的边10,它连接5和6,5还没有加入组织,所以使用这边。继续,发现此时已经连接了n-1条边,结束,最后图示如下:
本题与 https://www.acwing.com/problem/content/839/ 是姊妹题,其实Kruskal算法就是一个并查集的应用。
不像Prim算法,不用考虑边界,考虑循环N次啊,计算最小值啊,还要用堆进行优化啊,这个就是一个并查集,思路简单。
需要回答的问题
Q:只需要简单结构体即可,不需要邻接表或者邻接矩阵来存,为什么呢?
A:之所以使用邻接表或邻接矩阵,其实说白了,是按点存的,记录A点和B点的关系。
用结构体存储,其实是按边存的,就是题目说有一条A-B的边(权为C),我们就存了一个A-B权为C的边。
按点存麻烦(邻接表或邻接矩阵),按边存(结构体数组)简单。
C++ 代码
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 200010;
int n, m;
int p[N]; //并查集里面的p数组
struct Edge {
int a, b, w;
// 需要重载<号,利用w 进行排序
//这里重载小于号的目的是因为能用<号表示的数据才能够用标准库sort排序
bool operator<(const Edge &W) const {
return w < W.w;
}
} edges[N];
//并查集模板
int find(int x) {
if (p[x] != x) p[x] = find(p[x]);
return p[x];
}
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};
}
//利用STL进行快速排序
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; //a认b为祖宗,合并两个集合
res += w; //最小生成树中所有树边的权重之和
cnt++; //加入了多少条边
}
}
//如果加入的边数小于n-1(抽屉原理),说明不连通,连通图也有最小生成树,不连通没有
if (cnt < n - 1) puts("impossible");
else printf("%d\n", res);
return 0;
}
标签:int,Kruskal,查集,859,算法,连接,dis 来源: https://www.cnblogs.com/littlehb/p/15336857.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。