最小生成树
朴素版Prim算法
算法描述
- 所有距离初始化为正无穷 dist[i] <—— +oo
- n次迭代 for (int i = 0; i < n; i ++)
- 找到集合外距离最近的点赋值给t
- 用t更新其他点到集合的距离
- 把t加到集合中去 st[ti] = true
Prim算法求最小生成树
给定一个个顶点
条边的无向图,图中可能存在重边和自环,边权可能为负数。
求最小生成树的边权重之和,如果最小生成树不存在则输出impossible。
给定一张带权的无向图,其中
表示图中点的集合,
表示图中边的集合,
,
。
由中全部
个顶点和
中
条边构成的无向连通子图被称为
的一棵生成树,其中边权值之和最小的生成树被称为无向图
的最小生成树。
输入格式
第一行包含两个整数和
。
接下来行,每行包含三个整数
,表示点
和点
之间存在一条权值为
的边。
输出格式
一行,若存在最小生成树,则输出一个整数,表示最小生成树的数边权重之和,如果最小生成树不存在则输出impossible。
数据范围,
,
图中涉及边的边权的绝对值不超过10000。
输入样例
输出样例4 51 2 11 3 21 4 32 3 23 4 4
代码 ```cpp6
include
include
include
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;//尽早跳出循环防止TLEif (i && dist[t] == INF) return INF;//需要先累加再更新 防止自环加入的情况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;
}
<a name="Dut3t"></a>
### Kruskal算法
<a name="Fmj3t"></a>
#### 算法描述
1. 将所有边按权重从小到大顺序排序。时间复杂度O(mlogn)。
1. 枚举每条边a—>b,权重是c。
1. 如果a b不连通,将这条边加入集合中。
1. 反之舍去。
<a name="UU4uF"></a>
#### [Kruskal算法求最小生成树](https://www.acwing.com/problem/content/861/)
题目描述同上一题,仅数据范围不同。<br />**数据范围**<br />,<br />,<br />图中涉及边的边权的绝对值不超过1000。<br />**代码**
```cpp
#include <cstring>
#include <iostream>
#include <algorithm>
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;
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;
}
