zoukankan      html  css  js  c++  java
  • 最小生成树——kruskal算法

    1. 将n个顶点看成n个集合
    2. 按权值由小到大的顺序选择边,所选边应满足两个顶点不在同一个顶点集合内,将该边放到生成树的结合边中,同时也将该边的两个定点放到生成树的顶点集中
    3. 重复前两个(注意:所加的边不能构成环,所以在以下代码中用find函数检测将该边加入是否存在环)

    适合于稀疏图——顶点多边少

    #include <iostream>
    #include <vector>
    #include <algorithm>
    using namespace std;
    
    const int INF=0x3f3f;
    //边集数组 
    typedef struct Edg
    {
        int begin;//该边的起始点 
        int end;//该边的结束点 
        int weight;//该边的权值 
        Edg()
        {
            begin=end=weight=0;
        }
    }Edg;
    class Cmp
    {
        public:
            bool operator() (const Edg &a,const Edg &b)
            {
                return a.weight<=b.weight;    
            }
    };
    class Graph
    {
        private:
            int num;
            int e;
            vector<vector<int> > arr;
            vector<Edg> edg;
            vector<int> tree;
            int find(vector<int> &t,int n);//判断该边的两个定点是否都在最小生成树的集合中,v[t]=k,t是边的起始点,k是边的结束点 
        public:
            Graph();
            ~Graph();
            void kruskal();
    };
    Graph::Graph()
    {
        cout<<" num"<<endl;
        cin>>num;
        cout<<" e"<<endl;
        cin>>e;
        
        arr.resize(num);
        for(int i=0;i<num;++i)
        {
            arr.at(i).resize(num);
            fill(arr.at(i).begin(),arr.at(i).end(),INF);
        }
        
        edg.resize(num);//
        tree.resize(num,-1);//最小生成树的顶点集合,该集合中最多和图中的点一样多 
        
        cout<<" 输入边的两个端点&&权值"<<endl;
        pair<int,int> info;
        for(int i=0;i<e;++i)
        {
            cin>>info.first>>info.second;
            cin>>arr.at(info.first-1).at(info.second-1);
            arr.at(info.second-1).at(info.first-1)=arr.at(info.first-1).at(info.second-1);
        }
    }
    Graph::~Graph()
    {
        //cout<<"~Graph()"<<endl;    
    }
    int Graph::find(vector<int> &t,int n)
    {
        while(t.at(n)>0)
            n=t.at(n);
        return n;
    } 
    void Graph::kruskal()
    {
        //储存边的信息,只存储邻接矩阵的对角线右上部分,无向图 
        for(int i=0;i<num;++i)
            for(int j=i+1;j<num;++j)
            {
                if(arr.at(i).at(j)<INF)
                {
                    edg.at(i).begin=i;
                    edg.at(i).end=j;
                    edg.at(i).weight=arr.at(i).at(j);
                }
            }
        
        //按权值从小到大把边集排序
        sort(edg.begin(),edg.end(),Cmp());
        for(int i=0;i<num;++i)
        {
            int t=find(tree,edg.at(i).begin);
            int t1=find(tree,edg.at(i).end);
            if(t1!=t)
            {
                tree.at(t)=t1;
                cout<<"<"<<edg.at(i).begin<<","<<edg.at(i).end<<"> weight:"<<edg.at(i).weight<<endl;
            }
        }
    }
    int main()
    {
        Graph g;
        g.kruskal();
        return 0;
    }
  • 相关阅读:
    选择法与冒泡法
    递归法把一个整数通过字符串输出,谭浩强教材习题
    十六进制转十进制 2.0
    十六进制转十进制 谭浩强教材课后习题
    链表操作(改)--学生管理
    矩阵转置(有问题待补充)
    win10 PowerShell下安装vim编辑器
    wsl2+.net core+vscode开发调试环境
    git 一些常用的操作命令
    查看数据库所有表数据占用的空间大小
  • 原文地址:https://www.cnblogs.com/tianzeng/p/10458471.html
Copyright © 2011-2022 走看看