第23章:最小生成树

原创 2016年05月31日 14:13:38

对于任何一个连通无向图来说,其都存在一棵最小生成树,该树能够连接图中的所有顶点,并且具有最小的权重和。有两种算法能够求解该问题,一种是prim算法,另外一种是kruskal算法

prim算法

在prim算法的任一时刻,我们都可以看到一个已经被发现的顶点集,这些顶点集能够形成一棵树。此时,算法在每一个阶段找出一个新的顶点v,使之到已被发现的顶点集具有最少权重,并且把该新发现的顶点v添加到已经发现的顶点集中。当算法终止时,最小生成树形成。代码如下:

pair<vector<int>,vector<double>> prim_mst(const vector<list<int>>& graph,const vector<vector<double>>& edge_weights)
{
        const int source=0; //认为最小生成树的源顶点是标号为0的顶点;

        vector<bool> mstv(graph.size(),false); //标记结点是否被访问了

        const int NIL=-1;  //NIL表示不存在的顶点
        vector<int> pred(graph.size(),NIL);    //记录在最小生成树中每个结点的前向结点。
        vector<double> weight(graph.size(),DBL_MAX);//weight[v]记录的是未发现顶点v到已发现的所有顶点中最短的距离,
        //假设未发现顶点v到已发现顶点u的距离最少,则pred[v]=u,weight[v]为边(u,v)的权重;

        mstv[source]=true;
        for(auto iter=graph[source].begin();iter!=graph[source].end();++iter)
        {
                int tmp=*iter;
                pred[tmp]=source;
                weight[tmp]=edge_weights[source][tmp];
        }

        for(int i=0;i!=graph.size()-1;++i)
        {
                double min_weight=DBL_MAX;
                int v=-1;

                //找出连接树中结点所有边中具有最少权重边的顶点v.
                for(int j=0;j!=graph.size();++j)
                        if(!mstv[j]&&weight[j]<min_weight){
                                min_weight=weight[j];
                                v=j;
                        }

                if(v==-1)
                        throw runtime_error("the undirected graph is not connected");
                mstv[v]=true;

                for(auto iter=graph[v].begin();iter!=graph[v].end();++iter)
                {
                        int tmp=*iter;
                        if(!mstv[tmp]&&edge_weights[v][tmp]<weight[tmp]){
                                weight[tmp]=edge_weights[v][tmp];
                                pred[tmp]=v;
                        }
                                        }
        }

        return make_pair(pred,weight);
}

void prim_print_tree(const vector<list<int>>& graph, const vector<vector<double>>& edge_weights)
{
        auto mst=prim_mst(graph,edge_weights);
        const vector<int>& pred=mst.first;
        const vector<double>& weight=mst.second;


        double tree_weight=0;

        cout<<"tree edge\tcorresponding weight"<<endl;

        const int NIL=-1;  //NIL表示不存在的顶点
        for(int v=0;v!=graph.size();++v)
                if(pred[v]!=NIL){
                        tree_weight+=weight[v];
                        cout<<"( "<<pred[v]<<" to "<<v<<" )\t\t"<<weight[v]<<endl;
                }

        cout<<"minimum spanning tree weight: "<<tree_weight<<endl;
}

kruskal算法:

kruskal算法是连续地按照最小的权重选择边,并且当所选的边不产生回路时就把它作为取定的边。形式上,kruskal算法是在处理树的集合,也就是森林。开始的时候,存在|V|棵单结点树,而添加一边则将两棵树合并成一棵树,当算法终止时,就只剩下一棵树了,这棵树就是最小生成树。这与prim算法不同,prim算法是本来就有一棵树,这棵树慢慢长大最后变成了最小生成树,而kruskal算法是有不同树的集合,通过不断合并,最终变成一棵树。代码如下:

struct edge{
        edge(int s=0,int e=0,double w=0):start(s),end(e),weight(w){};
        bool operator<(const edge& e) const { return weight<e.weight;}

        int start,end;
        double weight;
};

vector<edge> kruskal_mst(const vector<list<int>>& graph,vector<edge>& graph_edge)
{
        DisjSets dj(graph.size());

        //将图中所有边按照权重从小到大排序;
        sort(graph_edge.begin(),graph_edge.end());

        vector<edge> mst_edge; //存储最小生成树中的边

        for(const auto& e:graph_edge)
        {
                int u=e.start;
                int v=e.end;

                int uset=dj.findSet(u);
                int vset=dj.findSet(v);
                if(uset!=vset){
                        mst_edge.push_back(e);
                        dj.unionSets(uset,vset);
                }
        }

        return mst_edge;
}

void kruskal_print_mst(const vector<list<int>>& graph,vector<edge>& graph_edge)
{
        auto mst_edge=kruskal_mst(graph,graph_edge);

        cout<<"edges\tcorresponding weight"<<endl;
        double tree_weight=0;
        for(const auto& e:mst_edge)
        {
                tree_weight+=e.weight;
                cout<<"( "<<e.start<<" to "<<e.end<<" )\t\t"<<e.weight<<endl;
        }

        cout<<"minimum spanning tree weight: "<<tree_weight<<endl;
}
版权声明:本文为博主原创文章,未经博主允许不得转载。

最小生成树(Prim算法)

要求:输入一个图,求出最小生成树。 输出最小生成树的边。 Prim算法 代码: #include typedef struct graph{ int vexnum,arcnum; int ed...
  • llwwlql
  • llwwlql
  • 2015年11月29日 18:39
  • 640

<C/C++图>最小生成树:Prim算法

一,最小生成树算法基本概念 最小生成树是数据结构中图的一种重要应用,它的要求是从一个有n个节点的带权完全图中选择n-1条边并使这个图仍然连通(也即得到了一棵生成树),同时还要考虑使树的权之和最小。最...

算法导论代码 第23章 最小生成树

第23章 最小生成树 22.2 Kruskal算法和Prim算法 22.2.1 Kruskal算法 #include #include #include #include typedef...

算法导论习题解-第23章最小生成树

#23.1-1 设(u,v)是连通图G中权重最小的边,证明(u,v)是某棵最小生成树的边。 解:将Vge...

算法导论 第23章 最小生成树 思考题

23-1 次最优的最小生成树     (c)根据普利姆算法计算出最小生成树,并得到树的parent数组(里面记录了各顶点的父顶点)。 运用动态规划方法即可,状态转移方程如下: 设顶点个数为V...

算法导论 第23章 最小生成树 斐波那契堆实现优先队列

最小生成树(Minimum Spanning Tree)问题     对于一个无向连通图G=(V,E),找出一个无回路的子集T包含于E,连接了所有的顶点,且其权值之和      为最小。由于T无回路...

最小生成树(算法导论第23章)

下面讨论的两种最小生成树算法都是贪心算法。贪心算法的每一步bixu

《算法导论》第23章 最小生成树 个人笔记

第23章 最小生成树 23.1 最小生成树的形成 23.2 Kruskal算法和Prim算法
  • Amber07
  • Amber07
  • 2017年06月15日 10:58
  • 190

算法导论 | 第23章 最小生成树

最小生成树(Minimum Spanning Tree),全称“最小权值生成树” 有两种具体的实现算法 1.Kruskal算法 2.Prim算法 两者都用到了贪心算法。...

算法导论 第23章 最小生成树

一、综述 1.minimum-spanning-tree problem 2.Kruskal's algorithm In Kruskal's algorithm, the set A is...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:第23章:最小生成树
举报原因:
原因补充:

(最多只允许输入30个字)