贪心算法之Kruskal

克鲁斯卡尔Kruskal算法同Prim算法一样,都是求最小生成树。Kruskal是不断的找最短边,加入集合,且不构成回路。

所以,我们可以给每个点定义一个集合,一边的起点和终点查看是否属于同一集合,如果是说明是回路,不成立,找下一条边。如果不属于同一集合,则成立,并把其中的一个集合的全部节点的集合改为另外一个集合,进行统一。

具体代码如下:

#include <iostream>
#include <algorithm>

using namespace std;
#define MAXNODE 1000

int n,m;
struct Edge{
    int u;
    int v;
    int w;
} e[MAXNODE * MAXNODE];

int nodeset[MAXNODE]; //每个顶点的集合

int Kruskal(int n);

bool Merge(int u, int i);

bool comp(Edge a, Edge b){
    return a.w < b.w;
}

void Init(int n){
    for(int i=0; i < n; i++){
        nodeset[i] = i;
    }
}

int main(){
    cout<<"请输入节点数n和边数m:";
    cin>>n>>m;
    Init(n);
    cout << "请输入节点边的权值:";
    for(int i = 0; i < m; i++){
        cin>>e[i].u>>e[i].v>>e[i].w;
    }
    sort(e, e+m, comp);
    int ans = Kruskal(n);
    cout<<ans<<endl;
}

int Kruskal(int n) {
    int ans = 0;
    for(int i = 0; i < m; i++){
        if(Merge(e[i].u, e[i].v)){//可以合并
            ans += e[i].w;
            n--;
            if(n==1)
                return ans;
        }
    }
    return 0;
}

bool Merge(int u, int i) {
    int a = nodeset[u];
    int b = nodeset[i];
    if(a == b)
        return false;
    //归并节点集合
    for(int j = 0; j < n; j++){
        if(nodeset[j] == b){
            nodeset[j] = a;
        }
    }
    return true;
}

同时,与Prim算法相比,因为Kruskal是按照边进行的,所以适合边少的情况,即稀疏图。而Prim是按照点进行的,比较适合稠密图。

猜你喜欢

转载自www.cnblogs.com/gpf951101/p/9130468.html