Kruskal算法

问题描述

有一张 \(n\) 个顶点、\(m\) 条边的无向图,且是连通图,求最小生成树。

算法简析

\(Kruskal\) 是一种求最小生成树的算法。
设该图为 \(G = (V, E)\)。最小生成树即所求为 \(G_T = (V_T, E_T)\),因为图是连通的,所以最小生成树会覆盖所有的顶点,即 \(V == V_T\)\(G_T\)真子图 \(G_A = (V_A, E_A)\)\(V_A == V\),构成森林(注意,这里与 \(Prim\) 并不一样。\(G_A\) 初始状态就覆盖所有顶点,每个顶点各自为一棵树)。
因为 \(G_A\) 已经覆盖了所有顶点,所以 \(G - G_A\) 只剩下 \(G\) 中所有的边 \(E\)。为了让 \(G_A\) 从森林变成一棵树,我们需要从 \(E\) 中挑选边加入 \(G_A\)。例如,我们选择 \(e(u, v)\) 加入 \(G_A\),本来独立的 \(u\)\(v\) 被连接起来,相当于 \(u\)\(v\) 各自所在的两棵树要合并成一棵树。
为了得到最小生成树,我们采用贪心策略,每次都从 \(E\) 中挑选最短的边 \(e(u, v)\),如果 \(u\)\(v\) 还不在一棵树上,就将该边加入 \(G_A\),同时合并两棵树。
为了能够高效地合并树,我们采用并查集

代码

typedef struct
{
    int from, to, worth;
} edge;

vector<edge> E;

// Kruskal
bool cmp(const edge &a, const edge &b)
{
    return a.worth < b.worth;
}

int kruskal(void)
{
    int ret = 0;
    init();
    sort(E.begin(), E.end(), cmp);          // 升序
    for (int i = 0; i < E.size(); i++)
    {
        edge e = E[i];
        if (!same(e.from, e.to))            // 判断是否在一棵树中
        {
            ret += e.worth;
            unite(e.from, e.to);            // 合并树
        }
    }
    return ret;
}

posted @   ltign  阅读(11)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示