Prim+Kruscal算法的C++实现

Kruscal原理:

使用贪心算法。先将所有边按照权值从小到大排序,每个点初始都是一个树(一个节点的树)。从前到后遍历边集,对于当前边x-y来说,如果x、y已经在我们的最小生成树里,那么跳过该边。

如果x、y至少有一个不在我们的最小生成树里,将该边加入最小生成树,并且将包含x的树和包含y的树合并为一棵树。(使用并差集的合并操作完成)

Kruscal算法适用于稀疏图

注:代码未验证正确性!

//Kruscal算法  2020年3月29日 21:41:19

//----------------------------------

vector<int> father; //并差集

void merge(int x,int y){
    int x_father=get_father(x),y_father=get_father(y);
    father[x]=y_father;
}

int get_father(int x){
    if(father[x]!=x){
        return father[x]=get_father(father[x]);
    }
    return x;
}
//-----------------------------------
struct edge     //有权边
{
    int point1;
    int point2;
    int weigh;
    edge(int x,int y,int z):point1(x),point2(y),weigh(z){}
};

//-----------------------------------

//求带权无向图的MST边权和
int Kruscal(){
    int points;//points:点数
    cout<<"输入点个数:"<<endl;
    cin>>points;
    father.resize(points);
    for(int i=0;i<points;++i){
        father[i]=i;
    }
    vector<edge> edges;    //edges:有权边的集合
    int r,s,t;
    while(cin>>r>>s>>t){
        edges.emplace_back(r,s,t);
    }
    sort(edges.begin(),edges.end(),[](const edge& a,const edge& b){return a.weigh<b.weigh;});   //按照权从小到大排序
    int res;    //MST的权和
    int edge_cnt=0;     //已经选入的边数
    for(const auto& edge:edges){
        int p1=edge.point1,p2=edge.point2;
        if(father[p1]==father[p2]){//p1、p2已经加入MST
            continue;
        }
        res+=edge.weigh;//该边加入MST
        ++edge_cnt;
        merge(p1,p2);//合并两个点
        if(edge_cnt>=points-1){//边数为点数-1时,完成了MST的构建
            break;
        }
    }
    return res;
}

 

 

 

Prim原理:

设图G顶点集合为U,首先任意选择图G中的一点作为起始点a,将该点加入集合V,再从集合U-V中找到另一点b使得点b到V中任意一点的权值最小,此时将b点也加入集合V;以此类推,现在的集合V={a,b},再从集合U-V中找到另一点c使得点c到V中任意一点的权值最小,此时将c点加入集合V,直至所有顶点全部被加入V,此时就构建出了一颗MST。因为有N个顶点,所以该MST就有N-1条边,每一次向集合V中加入一个点,就意味着找到一条MST的边。

Prim算法适用于稠密图 

注:代码未验证正确性!

//Prim算法 2020年3月29日 22:49:14


int Prim(){
    int points;//points:点数
    cout<<"输入点个数:"<<endl;
    cin>>points;
    vector<vector<int>> matrix(points,vector<int>(points,INT32_MAX));   //邻接矩阵,matrix[i][j]不为0:i到j有边相连,权为matrix[i][j]
    int r,s,t;
    while(cin>>r>>s>>t){
        matrix[r][s]=t;
        matrix[s][r]=t;
    }
    int res=0;  //最小生成树的边权和
    vector<int> min_weigh(points,0);
    for(int i=1;i<points;++i){
        min_weigh[i]=matrix[0][i];
    }
    for(int i=0;i<points-1;++i){//循环points-2次
        int min_distance=INT32_MAX;
        int which_point;
        //选出一条拥有最小权值的边,该边满足:一端在已找到的MST内,一端不在
        for(int j=0;j<points;++j){
            if(min_weigh[j] and min_weigh[j]<min_distance){
                min_distance=min_weigh[j];
                which_point=j;
            }
        }
        res+=min_distance;
        min_weigh[which_point]=0;//把新找到的点加入MST
        //对min_weigh数组进行更新,可能从which_point出发会有更小权的满足要求的边
        for(int j=0;j<points;++j){
            if(matrix[which_point][j]<min_weigh[j]){
                min_weigh[j]=matrix[which_point][j];
            }
        }
    }return res;
}

 

上一篇:c++ 友元函数简单使用


下一篇:二叉树的下一个结点