简单的kruskal算法

转载请注明来自 b0t0w1’blog

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

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

就用百度百科的图:
这里写图片描述
答案应该是这样的:
这里写图片描述
最大路径为 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;
}

输入样例:
这里写图片描述
输出样例:
这里写图片描述

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

转载请注明来自 b0t0w1’blog

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值