基本概念
树(Tree)
如果一个无向连通图中不存在回路,则这种图称为树。
生成树 (Spanning Tree)
无向连通图G的一个子图如果是一颗包含G的所有顶点的树,则该子图称为G的生成树。
生成树是连通图的极小连通子图。这里所谓极小是指:若在树中任意增加一条边,则将出现一条回路;若去掉一条边,将会使之变成非连通图。
最小生成树
一个带权值的连通图。用$n-1$条边把$n$个顶点连接起来,且连接起来的权值最小。
应用场景
设想有9个村庄,这些村庄构成如下图所示的地理位置,每个村庄的直线距离都不一样。若要在每个村庄间架设网络线缆,若要保证成本最小,则需要选择一条能够联通9个村庄,且长度最小的路线。
Kruskal算法
知识点:数据结构——并查集
基本思想
始终选择当前可用、不会(和已经选取的边)构成回路的最小权植边。
具体步骤:
1. 将所有边按权值进行降序排序
2. 依次选择权值最小的边
3. 若该边的两个顶点落在不同的连通分量上,选择这条边,并把这两个顶点标记为同一连通分量;若这条边的两个顶点落到同一连通分量上,舍弃这条边。反复执行2,3,直到所有的都在同一连通分量上。【这一步需要用到上面的并查集】
模板题:https://www.luogu.org/problem/P3366
#include <iostream> #include <algorithm> using namespace std; int pre[5005]; int n, m; //n个定点,m条边 struct ENode { int from, to, dis; bool operator<(ENode p) { return dis < p.dis; } }M[200005]; int Find(int x) { return x == pre[x] ? pre[x] : pre[x] = Find(pre[x]); } int kurskal() { sort(M, M + m); int N = n, res = 0; for (int i = 0; i < m && N > 1; i++) { int fx = Find(M[i].from), fy = Find(M[i].to); if (fx != fy) { pre[fx] = fy; N--;//找到了一条边,当N减到1的时候表明已经找到N-1条边了,就完成了 res += M[i].dis; } } if (N == 1)//循环做完,N不等于1 表明没有找到合适的N-1条边来构成最小生成树 return res; return -1; } int main() { cin >> n >>