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

    最小生成树

    概念:
    一个有 n 个结点的连通图的生成树是原图的极小连通子图,且包含原图中的所有 n 个结点,并且有保持图连通的最少的边。
    简单来说:最小生成树就是在一个连通图(每个点都相连的无向图)中使得权值和最小的树,保证每个点都在里面。
    最小生成树其实是最小权重生成树的简称。
    最小生成树又叫“MST”。
    应用:
    例如:要在n个城市之间铺设光缆,主要目标是要使这 n 个城市的任意两个之间都可以通信,但铺设光缆的费用很高,且各个城市之间铺设光缆的费用不同,因此另一个目标是要使铺设光缆的总费用最低。这就需要找到带权的最小生成树。
    求最小生成树的方法:
    最小生成树可以用kruskal(克鲁斯卡尔)算法或prim(普里姆)算法求出。
    prim算法的时间复杂度不依赖于排序算法,并且主要与点的个数有关,适用于密集图。
    kruskal算法需要排序,但使用幷查集可节省判断时间,主要与边的条数有关,适用于稀疏图。
    简单来说:Prim算法,适用于点少的图。Kruskal算法,适用于边少的图。

    Prim算法

    思想:
    贪心思想:每次选取最小边。
    算法描述:
    (1)输入:一个加权连通图,其中顶点集合为V,边集合为E;
    (2)初始化:Vnew = {x},其中x为集合V中的任一节点(起始点),Enew = {},为空;
    (3)重复下列操作,直到Vnew = V:
    a.在集合E中选取权值最小的边< u, v >,其中u为集合Vnew中的元素,而v不在Vnew集合当中,并且v∈V(如果存在有多条满足前述条件即具有相同权值的边,则可任意选取其中之一);
    b.将v加入集合Vnew中,将< u, v >边加入集合Enew中;
    (4)输出:使用集合Vnew和Enew来描述所得到的最小生成树。
    图例描述:
    这里写图片描述
    这里写图片描述
    这里写图片描述
    时间复杂度:
    顶点数v,边数e
    邻接矩阵:O(v)
    邻接表:O(elog2v)
    代码:

    #include<iostream>
    using namespace std;
    const int maxn=1000000;
    int n,k,tmp,ans,map[1001][1001],dis[maxn];
    bool flag[maxn];
    void prim()
    {
        for(int i=1;i<=n;i++)
        dis[i]=maxn;//初始化
        dis[1]=0;
        for(int i=1;i<=n;i++)
        {
            tmp=maxn;
            for(int j=1;j<=n;j++)
            if(!flag[j]&&tmp>dis[j])
            {
                tmp=dis[j];
                k=j;
            }//找出最小距离的节点 
            flag[k]=1;//把访问的节点做标记
            for(int j=1;j<=n;j++)
            if(!flag[j]&&dis[j]>map[k][j])
            dis[j]=map[k][j];//更新最短距离
        }
    }
    int main()
    {
        cin>>n;
        for(int i=1;i<=n;i++)//邻接矩阵储存权值 
          for(int j=1;j<=n;j++)
          cin>>map[i][j];
        prim();
        for(int i=1;i<=n;i++)
        ans+=dis[i];
        cout<<ans;
        return 0;
    }

    Kruskal算法

    基本思路:
    克鲁斯卡尔算法是在剩下的所有未选取的边中,找最小边,如果和已选取的边构成回路,则放弃,选取次小边。

    #include<iostream>
    #include<algorithm>
    using namespace std;
    int n,e,fa[101],sum=0;
    struct node
    {
        int o;
        int u;
        int t;
    }a[101];
    int find(int x)
    {
        if(father[x]!=x)
        father[x]=find(father[x])
        return father[x];
    }
    int cmp(node a,node b)        
    {
        return a.t < b.t;
    }
    void unionn(int x,int y)
    {
        int f1=find(x);
        int f2=find(y);
        if(f1!=f2)fa[f2]=f1;
    }
    int main()
    {
        int k=0;
        cin>>n>>e;
        for(int i=1;i<=e;i++)
        cin>>a[i].o>>a[i].u>>a[i].t;
        for(int i=1;i<=n;i++)
        fa[i]=i;
        sort(a+1,a+1+e,cmp);
        for(int i=1;i<=e;i++)
        {
            if(find(a[i].o)!=find(a[i].u))
            {
              unionn(a[i].o,a[i].u);
              sum=sum+a[i].t;
              k++;
            }
            if(k==n-1)break;
        }
        cout<<sum;
    }
    
  • 相关阅读:
    2013第49周四开发一定要细心
    2013第49周三IE9文档模式
    2013第49周二要转变
    2013第49周一jsp标签
    2013第48周11月工作小结
    2013第48周六记
    2013第48周五开发日记
    BZOJ 1269 文本编辑器 Splay
    审批流程设计方案-介绍(一)
    Web挖掘技术
  • 原文地址:https://www.cnblogs.com/cax1165/p/6071012.html
Copyright © 2011-2022 走看看