简单的kruskal算法

学kruskal算法时大神写的都很高端,所以写了一个最简单模板。

kruskal算法适用于 较少情况,需要用到并查集和路径压缩。

就用百度百科的图:
简单的kruskal算法_第1张图片
答案应该是这样的:
简单的kruskal算法_第2张图片
最大路径为 39

代码如下

#include<stdio.h>
#include<iostream>
#include<algorithm>
using namespace std;

//最大结点数
#define MAX_N 100
//最大边数
#define MAX_M 4450
//储存边的信息
struct Edge{
    int l;        //边的结点1
    int r;        //边的结点2
    int v;        //边的权值
};

Edge edge[MAX_M];
int N,M;

//储存根节点
int father[MAX_N];
//储存某结点的轶
int son[MAX_N];
//最短路径长度
int sum = 0;

//按照边的权值排序
bool cmp (const Edge &a, const Edge &b){
    return a.v < b.v;
}

/*寻找根节点,用到路径压缩。 所谓路径压缩,就是第一次寻找时直接修改了father[]数组, 直接指向根节点,而不是每次查询都要使用father[]一级一级往上跳, 而是直接跳到根节点。 */
int findfather(int x){
    if (x != father[x]){
        father[x] = findfather(father[x]);
    }
    return father[x];
}

//将不能构成环的边的权值加入到sum中
void add(int a, int b, int v){
    sum += v;
    if (a == b){
        return;
    }
    /* 根据结点轶的不同,将轶小的结点的父亲指向轶大的结点 ps:鄙人理解: 看过许多大神算法,将各两节点连接起来的方法有些不同。 这里我只是最简单的谁大谁就是根节点。 其实虽然方法不同,连接结果不同,但是kruskal算法并不关心树的具体结构, 它只关心一个点的根节点是谁即可,至于两点之间有哪些点,经过那些点不重要 */
    if (son[a] < son[b]){
        father[a] = b;
        son[b] += son[a];
        return;
    }
    else{
        father[b] = a;
        son[a] += son[b];
        return;
    }
}

void kruskal(){
    for (int i = 0; i < M; i++){
        int a = findfather(edge[i].l);
        int b = findfather(edge[i].r);
        if (a != b){
            add(a,b,edge[i].v);
        }
    }
}

int main(){
    freopen("in.txt", "r", stdin);
    freopen("out.txt", "w", stdout);
    //读入点数与边数
    scanf("%d%d", &N, &M);
    //读入边的信息
    for (int i = 0; i < M; i++){
        scanf("%d%d%d", &edge[i].l, &edge[i].r, &edge[i].v);
    }
    //按权值排序
    sort(edge, edge + M, cmp);
    //初始化father[]和son[]数组
    for (int i = 0; i < N; i++){
        father[i] = i;
        son[i] = 1;
    }
    kruskal();
    printf ("%d", sum);
    return 0;
}

输入样例:
简单的kruskal算法_第3张图片
输出样例:
简单的kruskal算法_第4张图片

ps: 还可以做改进,可以构造visit[]数组,访问过的不再访问。

你可能感兴趣的:(算法,kruskal)