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

    最小生成树算法

    是图论的一种算法

    用N个点用N-1条边连成一棵树

    所以在图中选N个点与N-1条边

    使在所有方案中和最小

    1°:

    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来描述所得到的最小生成树。
     
    这个算法你就当个笑话看看吧,反正也不常用
     

    Kruskal算法

      假设 WN=(V,{E}) 是一个含有 n 个顶点的连通网,则按照克鲁斯卡尔算法构造最小生成树的过程为:先构造一个只含 n 个顶点,而边集为空的子图,若将该子图中各个顶点看成是各棵树上的根结点,则它是一个含有 n 棵树的一个森林。之后,从网的边集 E 中选取一条权值最小的边,若该条边的两个顶点分属不同的树,则将其加入子图,也就是说,将这两个顶点分别所在的两棵树合成一棵树;反之,若该条边的两个顶点已落在同一棵树上,则不可取,而应该取下一条权值最小的边再试之。依次类推,直至森林中只有一棵树,也即子图中含有 n-1条边为止。
     
    然后上代码:
     1 #include<iostream>
     2 #include<cstdio>
     3 #include<algorithm>
     4 
     5 using namespace std;
     6 
     7 int f[300000];
     8 
     9 struct point{
    10     int x;
    11     int y;
    12     int z;
    13 }edge[300000];
    14 
    15 bool cmp(point a,point b)
    16 {
    17     return a.z<b.z;
    18 } 
    19 
    20 inline int Find(int a)
    21 {
    22     if(f[a]!=a) f[a]=Find(f[a]);
    23     return f[a];
    24 }
    25 
    26 inline void join(int a,int b)
    27 {
    28     int fa=Find(a);
    29     int fb=Find(b);
    30     if(fa!=fb) f[fa]=fb;
    31 }
    32 
    33 int main(void)
    34 {
    35     
    36     int n,m;
    37     
    38     scanf("%d%d",&n,&m);
    39     
    40     for(register int i=1;i<=m;i++)
    41         scanf("%d%d%d",&edge[i].x,&edge[i].y,&edge[i].z);
    42     
    43      sort(edge+1,edge+1+m,cmp);
    44     
    45      for(register int i=1;i<=n;i++)
    46         f[i]=i;
    47     
    48     int tot=0;
    49     
    50     int k=0;
    51 
    52     for(int i=1;i<=m;i++)
    53     {
    54     
    55         if(Find(edge[i].x) != Find(edge[i].y))
    56         {
    57             join(edge[i].x,edge[i].y);
    58             tot+=edge[i].z;
    59             k++;
    60         }
    61         if(k==n-1) break;
    62 
    63     }
    64     
    65     printf("%d",tot);
    66 }

    克鲁斯卡尔算法使用的了

    并查集思想

    快速排序

    优先连权值更大的边

    复杂度为 O(mlogm)

    而普利姆算法则采用dp思想,复杂度为 O(N^2),优化后达到 O(mlogn)

    综合比对来看

    1°Prim在稠密图中比Kruskal优,稀疏图劣

    2°Prim在任何情况下均有令人满意的时间复杂度,代价就是空间复杂度极高,并且代码极其恶心

    但是时间复杂度不能说明一个算法的优劣性质

    所以考试,你想用啥就用啥。

  • 相关阅读:
    Linux kernel pwn (四): Bypass SMEP
    Linux kernel pwn(三):Double Fetch
    Linux kernel pwn (二):UAF
    vue安装
    html标签
    javascript简介
    html样式 CSS(Cascading Style Sheets)
    html标签
    scala基础——scala变量
    elasticsearch日常维护
  • 原文地址:https://www.cnblogs.com/-Iris-/p/12691529.html
Copyright © 2011-2022 走看看