【学习笔记】最小生成树

最小生成树

What?

我们定义无向连通图的 最小生成树(Minimum Spanning Tree,MST)为边权和最小的生成树.

也就是给定一个图,找到一颗当中的树,使得图联通、权值之和最小

Kruskcal

主体思想是贪心,是从小到大加入边。


流程图
graph TD A[开始] --> B[将所有边按权重升序排序] B --> C[初始化并查集] C --> D[遍历每条边] D --> E{是否形成环?} E -->|否| F[加入MST并合并集合] E -->|是| G[跳过该边] F --> H{边数 = V-1?} H -->|是| I[结束] H -->|否| D G --> D

但是有一个问题,在“是否形成环”

抽象一点地说,维护一堆 集合,查询两个元素是否属于同一集合,合并两个集合.

其中,查询两点是否连通和连接两点可以使用并查集维护.

综述一下:为了造出一棵最小生成树,我们从最小边权的边开始,按边权从小到大依次加入,如果某次加边产生了环,就扔掉这条边,直到加入了 \(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


参考:最小生成树 - OI Wiki

posted @ 2026-02-04 21:59  ExAll  阅读(0)  评论(0)    收藏  举报