算法笔记---Kruskal算法

71 篇文章 0 订阅
41 篇文章 3 订阅

Kruskal算法:用来求解最小生成树的算法,同样使用贪心思想,只不过是边的权值最小来贪心。

Prim算法和Kruskal算法都是求解最小生成树的算法
只是Prim算法在执行时,是枚举图中所有结点,故比较适用稠密图(即结点少,边多),而Kruskal算法在执行时,是枚举所有边,故比较适用稀疏图(即结点多,边数少)。

Kruskal算法:
1、构造结构体,里面存放边的起始结点,终止结点,边的权值。

struct edge{
int start;//起始结点
int end;//终止结点
int weight;//边的权值
};

2、将边按照从小到大排序。
3、枚举所有边,若边的起始结点和终止结点不在一个集合中。则合并两个结点,然后把当前的边加入到最小生成树中,并更新最小生成树的总的边权。
4、重复上述过程,直到最小生成树的中有 n - 1 条边,n为结点数,退出循环。
5、检查最小生成树的边的条数是否为 n - 1,若不是,则表示该图为非连通图,返回-1,否则返回最小生成树总的边权。

样例:

输入:
6 10//6个顶点,10条边。以下10行为10条边
0 1 4//边0->1与1->0的边权为4,下同
0 4 1
0 5 2
1 2 1
1 5 3
2 3 6
2 5 5
3 4 5
3 5 4
4 5 3
输出:
11

解题思路;
使用并查集来表示两个结点是否在一个集合中,若不在,就合并(这是并查集的方法)
若并查集不是很清楚的,可以看 算法笔记—并查集 这部分。

下面为实现代码:

#include<iostream>
#include<algorithm>
using namespace std;
const int max_v = 110;//点的最大值
const int max_e = 10010;//边的最大值
struct edge
{
    int start;//起始结点
    int end;//终止结点
    int weight;//两结点之间的边
}E[max_e];//表示最多有max_e 条边

bool cmp(edge e1,edge e2){
    return e1.weight < e2.weight;
}

int father[max_v];//并查集数组

/**
 * @description: 查找当前结点的父结点
 * @param : 要查找的结点
 * @return: 返回x的根结点
 */
int find_father(int x){
    int temp = x;//暂时存放需要查询的结点
    while (x != father[x])
    {
        x = father[x];
    }
    //此时 temp 的根结点为 x

    //下面为路径压缩
    while (temp != father[temp])
    {
        int z = temp;
        temp = father[temp];
        father[z] = x;
    }
    return x;
}

/**
 * @description: kruskal算法
 * @param : n 表示结点数; m 表示边数
 * @return: 返回最小生成树的边权之和
 */
int kruskal(int n,int m){
    int result = 0;//最小生成树的边权之和
    int edge_num = 0;//表示当前最小生成树的边数
    //初始化father数组
    for(int i = 0;i < n;i++){
        father[i] = i;
    }
    sort(E,E + m,cmp);//将边的权值按照从小到大的顺序排列
    //枚举所有的边
    for(int i = 0;i < m;i++){
        int start_father = find_father(E[i].start);
        int end_father = find_father(E[i].end);
        if(start_father != end_father){
            father[start_father] = end_father;//合并集合
            result += E[i].weight;
            edge_num++;
            if(edge_num == n - 1){
                //边数等于结点数 - 1 即已经为最小生成树边的最大值
                break;
            }
        }
    }
    if(edge_num != n - 1){
        //表示给定的图不是连通图
        return -1;
    }
    return result;
}

int main(){
    int n,m;
    cin >> n >> m;
    for(int i = 0; i < m; i++){
        cin>>E[i].start>>E[i].end>>E[i].weight;
    }
    int result = kruskal(n,m);
    cout<<result<<endl;
    system("pause");
    return 0;
}

运行结果:

运行结果

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值