zoukankan      html  css  js  c++  java
  • 【最小生成树之Kruskal算法】

    看完之后推荐再看一看【最小生成树之Prim算法】-C++

    定义:一个有 n 个结点的连通图的生成树是原图的极小连通子图,且包含原图中的所有 n 个结点,并且有保持图连通的最少的边。最小生成树可以用kruskal(克鲁斯卡尔)算法或Prim(普里姆)算法求出。 。
    ​在一给定的无向图G = (V, E) 中,(u, v) 代表连接顶点 u 与顶点 v 的边(即),而 w(u, v) 代表此边的权重,若存在 T 为 E 的子集(即)且为无循环图,使得

    的 w(T) 最小,则此 T 为 G 的最小生成树。

    最小生成树其实是最小权重生成树的简称。

    许多应用问题都是一个求无向连通图的最小生成树问题。例如:要在n个城市之间铺设光缆,主要目标是要使这 n 个城市的任意两个之间都可以通信,但铺设光缆的费用很高,且各个城市之间铺设光缆的费用不同;另一个目标是要使铺设光缆的总费用最低。这就需要找到带权的最小生成树。

    这一章主要介绍Kruskal算法。

    Kruskal算法的时间复杂度:O(m*log(n))(点数n边数m)

    主要思路:

    输入之后对边权值进行排序,然后按边权值从小到大进行合并(merge)操作,如果操作成功(被合并的两个点不在一棵树上),则把这两个顶点的边权值加入总数,最后输出total即可。
    主要使用:

    “并查集。”

    洛谷P3366【模板】最小生成树
    这道题我第一次是用Kruskal来写的,具体思路再讲解一下。
    首先把get和merge函数写好,为了方便,我把merge写成了bool类型:如果成功合并(要求合并的两个顶点不在一棵树上)就返回true。
    然后是最正常的运用结构体进行循环读入,读入完成之后写cmp排序函数按边权值从小到大进行排序。
    接下来才和并查集扯上关系,所以要重新定义fa数组,然后进行初始化;

    核心代码

    	int cnt=0;
        int total=0;
        for(int i=1;i<=p;i++)//p为边数
        {
            if(merge(mp[i].u,mp[i].v))
            {
                cnt++;
                total+=mp[i].w;
                if(cnt==p-1) break;
            }
        }
    

    这段代码主要是为了统计权值和。把权值从最小到最大跑一遍,如果能够合并就合并然后加进total即可。然后就没什么难的了emm。
    下面贴代码;

    参考代码:

    #include<bits/stdc++.h>
    using namespace std;
    struct noded
    {
        int u,v;
        int w;
        noded(){}
        noded(int uu,int vv,int ww)
        {
            u=uu,v=vv,w=ww;
        }
    }mp[200010];
    bool cmp(noded x,noded y)
    {
        return x.w<y.w;
    }
    int fa[5010];
    int get(int x)
    {
        if(fa[x]==x)return x;
        else
        {
            fa[x]=get(fa[x]);
            return fa[x];
        }
    }
    bool merge(int x,int y)
    {
        int r1=get(x),r2=get(y);
        if(r1!=r2)
        {
            fa[r1]=r2;
            return true;
        }
        else return false;
    }
    int ans[250010];
    void init()
    {
        for(int i=1;i<=5000;i++)
        {
            fa[i]=i;
        }
    }
    int main()
    {
        //sqrt(pow((x1-x2),2)+pow((y1-y2),2));
        int n,p;
        cin>>n>>p;
        for(int i=1;i<=p;i++)
        {
            cin>>mp[i].u>>mp[i].v>>mp[i].w;
        }
        sort(mp+1,mp+1+p,cmp);
        //for(int i=1;i<=k;i++)
        //{
        //  cout<<endl<<mp[i].w;
        //}
        init();
        int cnt=0;
        int total=0;
        for(int i=1;i<=p;i++)
        {
            if(merge(mp[i].u,mp[i].v))
            {
                cnt++;
                total+=mp[i].w;
                if(cnt==p-1) break;
            }
        }
        cout<<total<<endl;
        return 0;
    }
    

    ov.

    个人博客地址: www.moyujiang.com 或 moyujiang.top
  • 相关阅读:
    python进程和线程(五)
    java开发常用Linux命令
    IntelliJ IDEA中Maven插件无法更新索引之解决办法
    Spring事务配置的五种方式
    思考,快与慢(读书笔记)
    freemarker,jsp,velocity比较
    java学习之路经验总结
    iBATIS源码分析
    freemarker的使用心得
    javaScript中的关键字和保留字
  • 原文地址:https://www.cnblogs.com/moyujiang/p/11167775.html
Copyright © 2011-2022 走看看