权重最小生成树的思想与Kruskal算法

晚上做携程的笔试题,附加题考到了权重最小生成树。OMG,就在开考之前,我还又看过一遍这内容,可因为时间太紧,也从来没有写过代码,就GG了。又吃了眼高手低的亏。这不,就好好总结一下,亡羊补牢。

权重最小生成树问题是指在一棵无向全连接图中找到一个无环子集T,既能将所有的结点连接起来,又具有最小的权重和。

    解决问题的核心是每次找到一条安全边加入到边集合A中,使得A仍然是某棵最小生成树的子集。

    Kruskal找到安全边的方法是:在所有连接森林中两棵不同树的边里面,找到权重最小的边(u,v),(1)如果u和v位于不同的子树,则该边就是一个安全边,将u和v位于的子树合并起来;(2)如果u和v位于相同子树,则该边不是一个安全边,如果将两棵子树连接起来,就会形成一个环。

我用详细注释的代码说明问题:

//合并节点a和b所属的两棵子树
void Union(int a, int b, int V,vector<int>& root)
{
    int root_a = root[a],root_b = root[b];
    //把b所在树的所有顶点都移植过去给a...  

    for (int i = 0; i < V; i++)
        if (root[i] == root_b)
            root[i] = root_a;
}
//sort的比较函数
bool compare(const CEdge &a, const CEdge &b)
{
    return  a.weight < b.weight;
}
//Kruskal最小生成树算法
void Kruskal(int V, int E, vector<CEdge> &e,vector<int>& root)
{
    //以权重为参考值,排序所有边
    sort(e.begin(), e.end(), compare);
    int cnt = 0;
    for (int i = 0; i < E; i++)
        if (root[e[i].u]!=root[e[i].v]) //如果e[i].u和e[i].v不属于同一棵子树
        {
            cout << e[i].u << "---" << e[i].v << " "<<e[i].weight<<endl;//加入该边
            Union(e[i].u, e[i].v, V,root);           //合并两棵子树

            //易知最小生成树拥有V-1条边
            //如果已经组成最小生成树,就退出循环
            ++cnt;
            if (cnt >= V - 1)
                break;
        }
}
int main()
{
    int V = 4;
    vector<CEdge> edges;
    edges.push_back({ 0, 1, 1 });
    edges.push_back({ 0, 2, 2 });
    edges.push_back({ 0, 3, 3 });
    edges.push_back({ 1, 2, 4 });
    edges.push_back({ 1, 3, 5 });
    edges.push_back({ 2, 3, 2 });

    //使用一个vector来表示各个子树(即集合A),
    //root[i]=j,表示节点i与节点j位于同一子树上,并且所有位于此树的节点k,都有root[k]=j;
    //初始化root[i]=i,表示每棵子树只是一个节点
    vector<int> root(V, 0);
    for (int i = 0; i < V; ++i)
        root[i] = i;

    //执行算法
    Kruskal(V, edges.size(), edges, root);

    while (1);
    return 0;
}

程序输出:

0---1 1
0---2 2
2---3 2

时间: 2024-08-04 05:00:24

权重最小生成树的思想与Kruskal算法的相关文章

最小生成树-Prim算法和Kruskal算法

原文链接:http://www.cnblogs.com/biyeymyhjob/archive/2012/07/30/2615542.html Prim算法 1.概览 普里姆算法(Prim算法),图论中的一种算法,可在加权连通图里搜索最小生成树.意即由此算法搜索到的边子集所构成的树中,不但包括了连通图里的所有顶点(英语:Vertex (graph theory)),且其所有边的权值之和亦为最小.该算法于1930年由捷克数学家沃伊捷赫·亚尔尼克(英语:Vojtěch Jarník)发现:并在195

转载:最小生成树-Prim算法和Kruskal算法

本文摘自:http://www.cnblogs.com/biyeymyhjob/archive/2012/07/30/2615542.html 最小生成树-Prim算法和Kruskal算法 Prim算法 1.概览 普里姆算法(Prim算法),图论中的一种算法,可在加权连通图里搜索最小生成树.意即由此算法搜索到的边子集所构成的树中,不但包括了连通图里的所有顶点(英语:Vertex (graph theory)),且其所有边的权值之和亦为最小.该算法于1930年由捷克数学家沃伊捷赫·亚尔尼克(英语:

[转载]最小生成树-Prim算法和Kruskal算法

转载地址:http://www.cnblogs.com/biyeymyhjob/archive/2012/07/30/2615542.html 自己在学,感觉这个讲的很不错,就转载了. Prim算法 1.概览 普里姆算法(Prim算法),图论中的一种算法,可在加权连通图里搜索最小生成树.意即由此算法搜索到的边子集所构成的树中,不但包括了连通图里的所有顶点(英语:Vertex (graph theory)),且其所有边的权值之和亦为最小.该算法于1930年由捷克数学家沃伊捷赫·亚尔尼克(英语:Vo

最小生成树Prim算法和Kruskal算法

Prim算法(使用visited数组实现) Prim算法求最小生成树的时候和边数无关,和顶点树有关,所以适合求解稠密网的最小生成树. Prim算法的步骤包括: 1. 将一个图分为两部分,一部分归为点集U,一部分归为点集V,U的初始集合为{V1},V的初始集合为{ALL-V1}. 2. 针对U开始找U中各节点的所有关联的边的权值最小的那个,然后将关联的节点Vi加入到U中,并且从V中删除(注意不能形成环). 3. 递归执行步骤2,直到V中的集合为空. 4. U中所有节点构成的树就是最小生成树. 方法

【图论】【最小生成树】Prim和Kruskal算法

在数据结构的教材上,讲到的图的最小生成树算法有两种,一种是Prim(普利姆)算法,一种是Kruskal(克鲁斯卡尔)算法. 两种算法的生成思路有所不同: Prim算法: 算法思想: 算法思想就是每次找到一个距离生成集合最近的点,加入,然后更新距离剩余点之间的距离,继续迭代. 算法步骤: 1.任意选择一个点作为起点,将该点标记为已加入最小生成树,使用一个数组表示该点已加入,join[i] = 1表示i点已加入集合: 2.将最小生成树集合作为整体,计算到其他未加入该集合的点(jion[i] == 0

HDU 1233 还是畅通工程【最小生成树入门题,Kruskal算法+Prim算法】

还是畅通工程 Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 39929    Accepted Submission(s): 18144 Problem Description 某省调查乡村交通状况,得到的统计表中列出了任意两村庄间的距离.省政府"畅通工程"的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路

【数据结构】 最小生成树(二)——kruskal算法

上一期说完了什么是最小生成树,这一期咱们来介绍求最小生成树的算法:kruskal算法,适用于稀疏图,也就是同样个数的节点,边越少就越快,到了数据结构与算法这个阶段了,做题靠的就是速度快,时间复杂度小. 网上一搜就知道大家都会先介绍prim算法,而我为什么不介绍prim算法呢?因为小编认为这个算法理解快,也很容易明白,可以先做个铺垫(小编绝不会告诉你小编是因为不会才不说的),kruskal算法核心思想是将一棵棵树林(也可以理解成子树)合并成一棵大树,具体做法如下:将一个连通图中不停寻找最短的边,如

图的最小生成树(一)—Kruskal算法

求下图的最小生成树: 数据给出如下: 第一行有两个数,n表示n个城市,m表示m条道路,接下来的m行,每行三个数a,b,c表示城市a到城市b的路程c. 现在需要解决的是,要求要最少的边让图连通(任意两点之间可以互相到达).要想让n个顶点的图连通,那么至少需要n-1条边.其实这里就是求一个图的最小生成树. 基本思路: 首先按照边的权值进行从小到大排序,每次从剩余的边中选择权值较小且边的两个顶点不在同一个集合内(将所有的顶点放入一个并查集中,判断两个顶点是否连通,只需判断两个顶点是否在同一个集合中,即

最小生成树(2)—— Kruskal算法

[由于时间不是很充足,现将完整代码放出,具体分析和思路,以后再更新] [详细代码]经codeblocks-13.12调试 1 #include<iostream> 2 #include<stdio.h> 3 #define MAX_ARC 1001 //边的最大权值 4 #define MAX_LINE 401 //图的最大边数 5 #define MAX_NUM 21 //图的最大顶点数 6 #define ERROR 0 7 #define OK 1 8 using names