【学习笔记】最小生成树
最小生成树
What?
我们定义无向连通图的 最小生成树(Minimum Spanning Tree,MST)为边权和最小的生成树.
也就是给定一个图,找到一颗当中的树,使得图联通、权值之和最小
Kruskcal
主体思想是贪心,是从小到大加入边。
流程图
但是有一个问题,在“是否形成环”
抽象一点地说,维护一堆 集合,查询两个元素是否属于同一集合,合并两个集合.
其中,查询两点是否连通和连接两点可以使用并查集维护.
综述一下:为了造出一棵最小生成树,我们从最小边权的边开始,按边权从小到大依次加入,如果某次加边产生了环,就扔掉这条边,直到加入了 \(n\) 条边,即形成了一棵树.
其中就有了问题:为什么边权最小的就一定能被MST覆盖?
证明
对于算法刚开始时,显然成立(最小生成树存在).
接下来考虑下一条进入的边 \(e\) :
\(T为MST\) , \(F为当前的生成树\)
如果 \(e \in T\) ,那么新的 \(F' = F\cup \{e\}\) ,显然 \(F' \subseteq T\) 依然满足。
否则 \(e \notin T\) 那么 \(T + e\) 就是一个环,为什么呢?
-
\(T\) 是一棵树,加入 \(e\)(它连接 \(e\) 中两个已经连通的点,因为
Kruskal算法加边时不形成环,但在 \(T\) 中这两个点已经通过其他路径连通)后,形成环 \(C\)(这个环存在于 \(T+e\) 中)。 -
什么?还没听懂?
- 在\(e\)之前,肯定已经选了边集 \(F\) (没有环)。
- 所以 \(T\) 是一棵树
- 而 \(e\) 是算法将要加入的边,因为树中任意两点已经有一条唯一路径
- 所以再加一条边就会形成环
-
对于上文举个栗子
- 一个图有四个顶点 \(T= \{(A, B), (B, C), (C, D) \}\)
- (这是生成树,连通所有顶点且无环)
- 图示:
A -- B -- C -- D - 上图是一条链
- 假设
Kruskal算法将要加入的边 \(e=(A,D)\),并且 \(e \notin T\)。 - 这样就形成了环
-
为什么一定有环
-
因为 \(T\) 是生成树,任意两点之间有且仅有一条路径。
当你在 \(T\) 中加一条新边 \(e\) (连接两点 \(u\) 和 \(v\))时:- 本来 \(u\) 到 \(v\) 在 \(T\) 中就有一条路径 \(P\)。
- 新边 \(e\) 与 \(P\) 一起构成一个环(\(P + e\))。
这就是树的基本性质:树中加任意一条新边必然产生一个环。
-
完成证明啦ヾ(≧▽≦*)o
例题
最优布线问题
求最小生成树模板
挂个代码:
vector<int> mn(n, INT_MAX);
vector<bool> in(n, false);
mn[0] = 0;
int count = 0;
for (int i = 0; i < n; i++)
{
int u = -1;
for (int j = 0; j < n; j++)
if (!in[j] && (u == -1 || mn[j] < mn[u]))
u = j;
in[u] = true;
count += mn[u];
for (int v = 0; v < n; v++)
if (G[u][v] < mn[v] && !in[v])
mn[v] = G[u][v];
}
cout << count << endl;
其他的好像没有什么好说的了
完结撒花ヾ(≧▽≦*)o

浙公网安备 33010602011771号