算法实践--最小生成树(Kruskal算法)

什么是最小生成树(Minimum Spanning Tree)

每两个端点之间的边都有一个权重值,最小生成树是这些边的一个子集。这些边可以将所有端点连到一起,且总的权重最小

下图所示的例子,最小生成树是{cf, fa, ab} 3条边

Kruskal算法

用到上一篇中介绍的不相交集合(并查集)

首先,定义V是端点的集合,E是边的集合,A为要求的最小生成树集合

  • 初始A为空集合,每个端点都作为单独的不相交集合
  • 将所有边根据其权重进行排序
  • 对每条边(v1, v2),如果其两个端点数据不同的不相交集,则将该边加到集合A中,同时将v1和v2合并
  • 最终得到的A即为最小生成树

生成过程的示例图

C++代码示例

struct Edge {
    char vertex1;
    char vertex2;
    int weight;
    Edge(char v1, char v2, int w):vertex1(v1), vertex2(v2), weight(w) {}
};

struct Graph {
    vector<char> vertice;
    vector<Edge> edges;
};

unordered_map<char, char> PARENT;
unordered_map<char, int> RANK;

char find(char vertex) {
    if (PARENT[vertex] == vertex)
        return PARENT[vertex];
    else
        return find(PARENT[vertex]);
}

void MST(Graph& g) {
    vector<Edge> res;

    for (auto c : g.vertice) {
        PARENT[c] = c;
        RANK[c] = 0;
    }

    sort(g.edges.begin(), g.edges.end(), [](Edge x, Edge y) {return x.weight < y.weight;});   // O(E*log(E))

    for (Edge e : g.edges) {         // O(E)
        char root1 = find(e.vertex1);  // 最差O(E),因为有记录深度,Find可以认为很快
        char root2 = find(e.vertex2);
        if (root1 != root2) {
            res.push_back(e);
            if (RANK[root1] > RANK[root2]) {
                PARENT[root2] = root1;
                RANK[root1]++;
            } else {
                PARENT[root1] = root2;
                RANK[root2]++;
            }
        }
    }

    for (Edge e : res) {
        cout << e.vertex1 << " -- " << e.vertex2 << "  " << e.weight << endl;
    }
}

void Union( char vertex_1, char vertex_2 ) {
}

int main() {

    char t[] = {‘a‘, ‘b‘, ‘c‘, ‘d‘, ‘e‘, ‘f‘};

    Graph g;
    g.vertice = vector<char>(t, t + sizeof(t)/sizeof(t[0]));

    g.edges.push_back(Edge(‘a‘, ‘b‘, 4));  // 稀疏图用链来表示(E = O(V))
    g.edges.push_back(Edge(‘a‘, ‘f‘, 2));  // 如果是密集图(E = O(V*V)), 用矩阵来表示
    g.edges.push_back(Edge(‘f‘, ‘b‘, 5));  // 大部分感兴趣的图是稀疏的
    g.edges.push_back(Edge(‘c‘, ‘b‘, 6));
    g.edges.push_back(Edge(‘c‘, ‘f‘, 1));
    g.edges.push_back(Edge(‘f‘, ‘e‘, 4));
    g.edges.push_back(Edge(‘d‘, ‘e‘, 2));
    g.edges.push_back(Edge(‘d‘, ‘c‘, 3));

    MST(g);

    return 0;
}

原文地址:https://www.cnblogs.com/logchen/p/10274863.html

时间: 2024-11-05 12:24:35

算法实践--最小生成树(Kruskal算法)的相关文章

SOJ4339 Driving Range 最小生成树 kruskal算法

典型的最小生成树 然后求最大的一条边 附上链接 http://cstest.scu.edu.cn/soj/problem.action?id=4339 需要注意的是有可能有 "IMPOSSIBLE" 的情况 这里用一个flag标记 记录所并的节点 只有flag = n时才能成功 负责就 "IMPOSSIBLE" 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring&g

最小生成树 kruskal算法简介

生成树--在一个图中的一个联通子图  使得所有的节点都被(访问) 最小生成树 (MST) 即联通子图的总代价(路程)最小 已知的一个图 有n个点 m条边 kruskal的算法如下 先对边从小到大排序 从最小的边起,不停的合并这条边的两个节点到一个集合,如果这条边的两个节点已经在一个集合里,则无视,否则形成回路(显然错误)直到所有的节点并到一个集合里 这里需要用到并查集来合并节点 1 int cmp(const int i,const int j) { 2 return w[i] < w[j];

最小生成树 Kruskal算法

Kruskal算法 1.概览 Kruskal算法是一种用来寻找最小生成树的算法,由Joseph Kruskal在1956年发表.用来解决同样问题的还有Prim算法和Boruvka算法等.三种算法都是贪婪算法的应用.和Boruvka算法不同的地方是,Kruskal算法在图中存在相同权值的边时也有效. 2.算法简单描述 1).记Graph中有v个顶点,e个边 2).新建图Graphnew,Graphnew中拥有原图中相同的e个顶点,但没有边 3).将原图Graph中所有e个边按权值从小到大排序 4)

无向图最小生成树Kruskal算法

问题 最小生成树的Kruskal算法 描述:有A.B.C.D四个点,每两个点之间的距离(无方向)是(第一个数字是两点之间距离,后面两个字母代表两个点):(1,'A','B'),(5,'A','C'),(3,'A','D'),(4,'B','C'),(2,'B','D'),(1,'C','D') 生成边长和最小的树,也就是找出一种连接方法,将各点连接起来,并且各点之间的距离和最小. 思路说明: Kruskal算法是经典的无向图最小生成树解决方法.此处列举两种python的实现方法.这两种方法均参考

最小生成树Kruskal算法的提出者Joseph Bernard Kruskal,Jr.

熟悉算法中的最小生成树的朋友都晓得有一个Kruskal算法,这个算法就是由题目中那个名字很长的人提出的.因为他功绩卓越,尊称他为Kruskal. Kruskal生于1928年1月29日,卒于2010年9月19日,美国人,维基里的词条中包含的头衔是:数学家.统计学家.计算机科学家.心理测量学专家. kruskal分别就读过芝加哥大学和普林斯顿大学,1954年获得博士学位. 下面链接中是一篇几年他的文章,从中可以了解他的更多成就.顺便说一句,他的父母和兄弟也都很牛. http://pan.baidu

算法8-4:Kruskal算法

Kruskal算法用于计算一个图的最小生成树.这个算法的步骤如下: 按照边的权重从小到达进行排序 依次将每条边增加到最小生成树中,除非这条边会造成回路 实现思路 第一个步骤需要对边进行排序,排序方法在之前的章节中已经介绍了很多,可以使用优先级队列进行实现,也可以使用归并排序进行实现,这里采用归并排序. 第二个步骤需要判断是否会造成回路.如果增加一条边会形成回路,那么这条边在增加之前,它两端的顶点必定是能够连通的.因此,在算法中使用并查集实现高效的判断. 代码 import java.util.L

ZOJ 1718 POJ 2031 Building a Space Station 修建空间站 最小生成树 Kruskal算法

题目链接:ZOJ 1718 POJ 2031 Building a Space Station 修建空间站 Building a Space Station Time Limit: 2 Seconds      Memory Limit: 65536 KB You are a member of the space station engineering team, and are assigned a task in the construction process of the statio

最小生成树——Kruskal算法

前面介绍了最小生成树和Prim算法,这篇博客继续记录Kruskal算法的相关内容. 算法思想: 1. 先将所有边按权值由小到大排序: 2. 从边集中选出第一条边(即权值最小的边),如果与树中现有的边不构成环,则将其加入树中: 3. 重复步骤2直至树中有n-1条边. 在实现上述算法之前,要先解决三个问题: 1. 如何表示一条边? 虽然我们尽量简化情景方便实现,但是边还是不能像节点一样简单地用一个数表示,因为它有三个必备的属性:起点.终点和权值.因此,我们创建以下结构体来表示边: 1 // 定义表示

最小生成树Kruskal算法

Kruskal算法就是把图中的所有边权值排序,然后从最小的边权值开始查找,连接图中的点,当该边的权值较小,但是连接在途中后会形成回路时就舍弃该边,寻找下一边,以此类推,假设有n个点,则只需要查找n-1条边即可. #include<stdio.h> #include<iostream> #include<algorithm> #include<string.h> using namespace std; const int maxn=1000; int v,l