c++最小生成树之克鲁斯卡尔

最小生成树有两个算法,一个是prim,一个是kruskarl。prim算法就相当于以点为主,来找最小生成树
而kruskarl算法就是着眼于边了

核心思想

1.将所有边按从小到大排序
2.枚举某一条边,若与边相连的两个点不在同一个集合,就合并这两个点,不然就跳过(此处会用到并查集),不会并查集的话可以看看我以前写的并查集
3.(重点)若边数=点数-1,则最小树成功生成。原理:这其实就是数学,一条边有两条端点,两条边因为共用一个端点,所以是三个端点(如下)

.___.___.

这就是三个点时边的情况

实现

原题
文字稿如下

题目描述

如题,给出一个无向图,求出最小生成树,如果该图不连通,则输出orz

输入输出格式

输入格式:
第一行包含两个整数N、M,表示该图共有N个结点和M条无向边。(N<=5000,M<=200000)

接下来M行每行包含三个整数Xi、Yi、Zi,表示有一条长度为Zi的无向边连接结点Xi、Yi

输出格式:
输出包含一个数,即最小生成树的各边的长度之和;如果该图不连通则输出orz

输入输出样例

输入样例#1: 复制
4 5
1 2 2
1 3 2
1 4 3
2 3 4
3 4 3
输出样例#1: 复制
7
说明

时空限制:1000ms,128M

数据规模:

对于20%的数据:N<=5,M<=20

对于40%的数据:N<=50,M<=2500

对于70%的数据:N<=500,M<=10000

对于100%的数据:N<=5000,M<=200000

我用了一个结构体来存储(也可以用链式前向星)

const int M=200100;
struct node{
    int x;//出发节点
    int y;//到达节点
    int w;//边长度
}a[M];

读入

cin>>n>>e;
    for(int i=1;i<=e;i++)scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].w);

排序

sort(a+1,a+e+1,cmp);

就只有这么一行。
sort其实是algorithm头文件的一个函数,用来排序,后面我会专门有一篇文章来讲它 。
cmp是一个函数,用来排序。

bool cmp(node x,node y){//注意开结构体类型
    if(x.w<y.w)return 1;//如果边 x的长度小于边y的长度,函数返回真,也就是要交换的意思
    if(x.w==y.w)//如果边的长度相同(只是为了判重)
        if(x.x>y.x)return 1;//返回 起点更大的
    return 0;
}

主程序

for(int i=1;i<=e;i++)
{
        if(getfather(a[i].x)!=getfather(a[i].y))
    {//如果点 x与点y不在同一个集合里
            ans+=a[i].w;//把这条边 的长度加入总和
            dad[getfather(a[i].x)]=a[i].y;//并 集过程
            p++;//p记录边的数量
        }
   }//因为题目数据,我就直接遍历了所有边

最后输出

cout<<ans;//输出总和

还是很简单吧?
完整代码:

#include <bits/stdc++.h>
using namespace std;
const int M=200100;
struct node{
    int x;
    int y;
    int w;
}a[M];
int n,e,dad[M],p=1,ans;

bool cmp(node x,node y){
    if(x.w<y.w)return 1;
    if(x.w==y.w)
        if(x.x>y.x)return 1;
    return 0;
}
int getfather(int x){
    if(x==dad[x])return x;
    dad[x]=getfather(dad[x]);
    return dad[x];
}
    
int main()
{
    cin>>n>>e;
    for(int i=1;i<=e;i++)scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].w);
    sort(a+1,a+e+1,cmp);
    for(int i=1;i<=n;i++)dad[i]=i;
    for(int i=1;i<=e;i++){
        if(getfather(a[i].x)!=getfather(a[i].y)){
            ans+=a[i].w;
            dad[getfather(a[i].x)]=a[i].y;
            p++;
        }
    }
    cout<<ans;
    return 0;
}
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 参见贪心算法——最小生成树算法 目录 1 最小生成树问题 2 贪心选择性质2.1 贪心选择框架——选择安全边2.2...
    王侦阅读 9,109评论 0 2
  • 前言 其实读完斯坦福的这本《互联网大规模数据挖掘》,让我感觉到,什么是人工智能?人工智能就是更高层次的数据挖掘。机...
    我偏笑_NSNirvana阅读 14,366评论 1 23
  • 这篇文章由 最小生成树-Prim算法和Kruskal算法 整理而来, 感谢这篇文章的作者 Prime算法 1. 概...
    爱上落入尘世间的你阅读 9,617评论 0 2
  • 一、定义 最小生成树(Minimum Spanning Tree,MST)仅针对加权连通无向图。对于一副加权连通无...
    null12阅读 7,011评论 0 0
  • 最小生成树是一个连通加权无向图中一棵权值最小的生成树。 Prim算法思想:设图G顶点集合为U,首先任意选择图G中的...
    乘瓠散人阅读 5,113评论 0 0