最小生成树

(克鲁斯卡尔算法) 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. 测试与爬虫—抓包神器之Charles

    前言 之前我们讲到过fiddler(https://www.cnblogs.com/zichliang/p/16067941.html),wireshark(https://www.cnblogs.c ...

  2. Unity的IPreprocessComputeShaders:深入解析与实用案例

    Unity IPreprocessComputeShaders Unity IPreprocessComputeShaders是Unity引擎中的一个非常有用的功能,它可以让开发者编译Compute ...

  3. ArrayList底层原理、线程安全及其相关集合(面试常问)

    一.ArrayList底层原理 1.特点及其原理:ArrayList底层基于数组实现,查找快,增删慢 2.ArrayList底层原理,初始化及调用add()方法添加元素: 默认初始化容量为10 第一次 ...

  4. MySql之锁

    MySql之锁 一.全局锁 对整个数据库加锁 应用:数据库所有表备份 二.表级锁 1.表锁 分为两类: 表共享读锁read lock 表独占写锁write lock 2.元数据锁 避免DML语句和DD ...

  5. JaCoCo助您毁灭线上僵尸代码

    一. 现状·问题 随着需求不断迭代,业务系统的业务代码突飞猛进,在你自豪于自己的代码量产出很高时,有没有回头看看线上真正的客户使用量又有多少呢? 费事费力耗费大量人力成本上线的功能,可能一年没人使用, ...

  6. Callback Function Essence

    Include Example Input: I am a. route execute finish. I am b. route execute finish. What is Callback ...

  7. 给DataTable添加额外字段

    //dt为DataTable dt.Columns.Add("字段名");//创建字段 //给新增字段赋值 foreach(DataRow item in dt.Rows) { i ...

  8. 关闭k8s的pod时减小对服务的影响

    在应用程序的整个生命周期中,正在运行的 pod 会由于多种原因而终止.在某些情况下,Kubernetes 会因用户输入(例如更新或删除 Deployment 时)而终止 pod.在其他情况下,Kube ...

  9. Electron包装网站的问题

    原文链接 原文链接 Preface 最近尝试了很多不错的在线工具,只是每次都要进入网站,有点麻烦,于是想到之前了解过的electron,尝试一下打包成本地应用. Contents 1.下载所有源文件 ...

  10. golang .(type)语法

    一直弄不懂 .(type) 是啥,在 liteide 中输出 (1+1).(type),提示: use of .(type) outside type switch 于是搜索到这个文章: 作者:翔云翔 ...