zoukankan      html  css  js  c++  java
  • 最小生成树

    GeneralLiu

    最小生成树

    就是在一个 n 个点的连通图里

    取 n-1 条边

    使 n 个点 连通

    并且 这 n-1 条边 的和 最小

    如 红边 是 最小生成树

     

    最小生成树 主要就是通过 下面的两种方法

    Prim算法 和 Kruskal算法 来解决

    然后  这两种算法 采用的思路 不同

    但是  到达同样的 结果

    具体选择  

    可以根据题目的 特点 或者 个人喜好

    我个人觉得 K算法 写起来很爽

    但理性地讲 

    P算法 的复杂度 主要取决于 节点数

    K算法 的复杂度 主要取决于    边数

    所以 当点一样多时 比较稀疏(边少)的图 用 K算法

              比较稠密(边多)的图 用 P算法

     

    Kruskal算法

     

    两步就能解决的

    相当容易理解的

    个人情有独钟的

    K算法

    两步

    既然最小生成树 一定要取 n-1 条边

    那么 取边的时候 就 能小则小 喽

    所以  第一步  

      将所有的边 按边权 从小到大排序

    第二步

    选边的时候 很明显地 “ 选前 n-1 条边” 是错的

    所以 从小到大 能选则选 直到选了 n-1 条为止

    第二步  简单的要死

    注释

    所谓 “能选则选” :

    因为 最小生成树 是树 是没有环的

    所以 选边的时候也不能出现 环

    每次成功 选出一条边 就把 边连接的两个连通块 合并

    所谓 “ 成功 选出 ”:

    该边的 两个端点 不在同一连通块里

    如果在同一个连通块里 就成环了 

    代码

    #include <bits/stdc++.h>
    using namespace std;
    
    const int maxn=100000+15;
    const int maxm=100000+15;
    struct Edge
    {
        int x,y,z;
    }edge[maxm];
    int n,m,tot;
    // 由小到大 
    bool cmp(Edge a,Edge b)
    {
        return a.z<b.z;
    }
    int top[maxn];
    
    // 判断连通块 的 时候 用到了 并查集 
    int found(int x)  
    {
        if (top[x]==x) return x;
        return top[x]=found(top[x]);
    }
    
    int main()
    {
        scanf("%d%d",&n,&m);
        tot=n-1;// 需要 取 tot 条边 
        for (int i=1;i<=m;i++)
        {
            scanf("%d%d%d",&edge[i].x,&edge[i].y,&edge[i].z);
        } 
        sort(edge+1,edge+m+1,cmp);  //  第一步 排序 
        for (int i=1;i<=n;i++) top[i]=i;  // 初始化 连通块 
        int ans=0;
        for (int i=1;tot;i++)
        {
            int fx=found(edge[i].x),fy=found(edge[i].y);
            // 可以 把 fx 理解为 x 所在 连通块 编号   fy 同理 
            if (fx!=fy) 
            {
                tot--; // 计数器 -1 
                ans+=edge[i].z;  //累加 答案 
                top[fx]=fy; //连通块合并 
            }
        }
        printf("%d
    ",ans);
        return 0;
     } 
    View Code

    Prim算法

    先选取一个 蓝点

    然后不断 把白点 加入蓝点 的一个过程

     

    1 初始化  V’={x}  E’={}  V'是蓝点

        x是随便一个节点

     

    2 重复下列操作   直到V’=V

    在E集合当中  选择最小的边 <u,v>

    使得 u∈V’   但是  v∉V’     u是蓝点 v是白点

    V’ 中加入节点 v    E’ 中加入<u,v>

     

    3 (V’,E’)则为所求的最小生成树。

     

    分析

    1    中 的 x 随便 一个点 即可

    2    一直 选最小的 连接 V' 与 !V’ 的 边

      这一步可用 heap 堆 (优先队列) 优化

      维护一个   u∈V’  但是  v∉V’  的边集

      就能 迅速取出 满足要求 的边

     

    代码

    #include <bits/stdc++.h>
    using namespace std;
    
    const int maxn=100000+15;
    const int maxm=100000+15;
    struct Edge
    {
        int x,y,z,next;
        Edge(int x=0,int y=0,int z=0,int next=0):x(x),y(y),z(z),next(next) {}
    }edge[maxm*2];
    const bool operator < (const Edge &a,const Edge &b)//定义 小根堆 
    {
        return a.z>b.z;
     } 
    int n,m;
    int sumedge,head[maxn];
    int ins(int x,int y,int z)
    {
        edge[++sumedge]=Edge(x,y,z,head[x]);
        return head[x]=sumedge;
    }
    priority_queue <Edge> que;
    int ans;
    bool boo[maxn];
    int main()
    {
        scanf("%d%d",&n,&m);
        for (int i=1;i<=m;i++)
        {
            int x,y,z;
            scanf("%d%d%d",&x,&y,&z);
            ins(x,y,z);
            ins(y,x,z);
        }
        memset(boo,false,sizeof(boo));  //  初始 全为 白点 
        boo[1]=true;  //  1 置为蓝点 
        for (int u=head[1];u;u=edge[u].next) que.push(edge[u]);// 堆中加边 
        for (int i=1;i<n;i++)    //总共要取出 n-1 条边 
        {
            Edge temp;
            temp=que.top();
            // 找到 满足 v  是 白点 
            for (;boo[temp.y];que.pop(),temp=que.top());
            que.pop();
            ans+=temp.z;
            boo[temp.y]=true;// 变蓝 
            for (int u=head[temp.y];u;u=edge[u].next)
             if (!boo[edge[u].y]) que.push(edge[u]);// 继续加 
        }
        printf("%d
    ",ans);
        return 0;
     } 
    View Code
  • 相关阅读:
    我们失去了,我们又没有失去什么
    人过 40
    KPI绩效考核为何在国内不管用?
    再也不必当心我的密码了,多个SAP 客户端自动输入密码
    大器晚成
    人际能量相吸定律
    SQL SERVER函数——表值函数的处理
    MS-SQL SERVER单列合并的四种常用方法
    实战 SQL Server 2008 数据库误删除数据的恢复
    唉,怎么一眨眼就老了!
  • 原文地址:https://www.cnblogs.com/1227xq/p/6816062.html
Copyright © 2011-2022 走看看