• 模板【kruskal】


    PART1

    1.实现:

    将每条边按权值从小到大进行排序

    (要用并查集维护)容边上两点不在同一个树,则合并

    2.时间复杂度:

    Kruskal 算法的时间复杂度由排序算法决定,若采用快排则时间复杂度为 O(Elog⁡E)

    总时间复杂度为 O(ElogE+V α(V)) 【α(V)近似看作常数】

    3.特别优势:

    1.prim只能用在连结成一个总集合的情况,如果是k个集合,那就只能用Kruskal

    2.kruskal算法不需要建图,只需要用并查集

    4.适用情况:

    5.需要注意的点:

    PART2

     可用代码

    #include<cstdio>
    #include<cmath>
    #include<algorithm>
    #include<set>
    #include<map>
    #include<cstring>
    #include<string>
    #include<vector>
    #include<queue>
    #include<iomanip>
    #include<iostream>
    using namespace std;
    const int N = 5e3+10;
    const int M = 2e5+10;
    #define inf 0x3f3f3f3f
    
    //kruskalEdge
    struct kruskalEdge
    {
        int u, v, w;
    } kE[M];
    //MergeFindSet
    int fa[N];
    int Get(int x)
    {
        if(fa[x] == x)
            return x;
        return fa[x] = Get(fa[x]);
    }
    inline void MergeFindSetInit(int &n)
    {
        for(int i = 1; i<= n; i++)
            fa[i] = i;
    }
    bool Merge(int u, int v)
    {
        int fu = Get(u);
        int fv = Get(v);
        if(fu != fv)
        {
            fa[fv] = fu;
            return true;
        }
        else
            return false;
    }
    //Kruskal
    bool KruskalCmp(kruskalEdge a, kruskalEdge b)
    {
        return a.w < b.w;
    }
    int Kruskal(int n, int m)
    {
        int sum = 0;
        MergeFindSetInit(n);
        sort(kE+1, kE+m+1, KruskalCmp);
        int cnt = 0;//记录合并了多少次
        for(int i = 1; i <= m; i++)
        {
            if(Merge(kE[i].u, kE[i].v))
            {
                cnt++;
                sum += kE[i].w;
            }
        }
        if(cnt == n-1)
            return sum;
        else
            return -1;
    }
    //in
    inline void KruskalIn(int &n, int &m)
    {
        cin >> n >> m;
        for(int i = 1; i <= m; i++)
        {
            cin >> kE[i].u >> kE[i].v >> kE[i].w;
        }
    }
    int main()
    {
        //freopen("in.txt","r", stdin);
        //freopen("out.txt","w", stdout);
        ios::sync_with_stdio(false);
        int n, m;
        KruskalIn(n, m);
        int ans = Kruskal(n, m);
        if(ans == -1)
            cout <<"no answer";
        else
            cout << ans << endl;
        return 0;
    }
    View Code

    PART3

    1.例题1:次小生成树

    给定一个无向连通图,求出它的边权总和第二小的生成树。

    解法:枚举最小生成树上的 n 条边,对于其中某条边,从图中删除它以后计算剩余图的最小生成树,一共 n−1棵。

    从这 n−1 棵生成树中找出最小的一棵,就是整个图的次小生成树。

    2.例题 2:边权极差最小生成树

    给定一个无向连通图,求出它所有生成树中,最大边权和最小边权之差最小的生成树。

    解法:利用例题 1 中给出的性质,枚举生成树上的最小边权 min_w,计算边权最小为 min_w的最小生成树,用当前最小生成树的最大边减去最小边来更新最终答案。

    PART4

    PART5

    口袋天空

  • 相关阅读:
    Android SDK Android NDK 官方下载地址
    编码转换工具 源码
    st_mode的剖析
    关于 python 字符编码的一些认识
    MFC中的argc和argv参数
    VC实现文件拖拽获取文件名
    CString 转 int
    《C语言程序设计实践教程》实验题源程序
    C语言 文件操作 结构体与文件 fgetc fputc fread fwrite
    C++语言 创建状态栏
  • 原文地址:https://www.cnblogs.com/bear-xin/p/14953717.html
Copyright © 2020-2023  润新知