• 关于最小生成树 Kruskal 和 Prim 的简述(图论)


    模版题为【poj 1287】Networking。

    题意我就不说了,我就想简单讲一下Kruskal和Prim算法。卡Kruskal的题似乎几乎为0。(●-`o´-)ノ

    假设有一个N个点的连通图,有M条边(不定向),求MST(Minimal Spanning Tree)最小生成树的值。

    1.Kruskal 克鲁斯卡算法

    概述:将边从小到大排序,依次将边两端的不在同一个联通分量/联盟的点分别加入一个个联盟内,将边也纳入,计入答案。最终N个点合并为一个联盟,也就是纳入联盟内的边达到N-1条就结束算法。
    实现:并查集。
    时间复杂度:O(m log m+m*k)≈O(m log m)
    应用:稀疏图(Sparse Graph, 由于主要看边数)
    注意——无须建2条双向边,因为每次纳入点,但时间复杂度又是按边算的。
    代码如下——

     1 #include<cstdio>
     2 #include<cstdlib>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<iostream>
     6 using namespace std;
     7 const int N=110,M=5010,D=10010;
     8 
     9 //这是无向边的图,不用建2倍的便关于方向的边。
    10 struct node
    11 {
    12     int x,y,d;
    13     node() {}//
    14     node(int x,int y,int d):x(x),y(y),d(d) {}//
    15     //bool operator < (const node& now) const
    16     //{  return d<now.d;  }
    17 }a[M];
    18 int fa[N];
    19 int n,m;
    20 
    21 bool cmp(node x,node y) {return x.d<y.d;}
    22 int mmin(int x,int y) {return x<y?x:y;}
    23 int ffind(int x)
    24 {//保持树的形态不变,顺便把遍历过的结点都改成树根的子节点,而不是之前子节点的子节点(这样要find要调用很多层)
    25     if (fa[x]!=x) fa[x]=ffind(fa[x]);
    26     return fa[x];
    27 }
    28 int Kruskal()
    29 {
    30     int i,k;
    31     int x,y,xx,yy;
    32     int cnt=0,ans=0;
    33     sort(a+1,a+1+m,cmp);
    34     for (i=1;i<=n;i++) fa[i]=i;
    35     for (i=1;i<=m;i++)//从最小的边开始选
    36     {
    37       x=a[i].x,xx=ffind(x);
    38       y=a[i].y,yy=ffind(y);
    39       if (xx!=yy)
    40       {
    41         cnt++,ans+=a[i].d;
    42         fa[xx]=yy;
    43         if (cnt==n-1) break;//边选够了
    44       }
    45     }
    46     return ans;
    47 }
    48 int main()
    49 {
    50     while (scanf("%d",&n)!=EOF && n)
    51     {
    52       scanf("%d",&m);
    53       int i,x,y,d;
    54       for (i=1;i<=m;i++)
    55       {
    56         scanf("%d%d%d",&x,&y,&d);
    57         a[i]=node(x,y,d);//
    58       }
    59       printf("%d
    ",Kruskal());
    60     }
    61     return 0;
    62 }
    Kruskal

    2.Prim 普里姆算法

    概述:先将1个点纳入联盟内,于是每次新纳入离联盟最近的点(看联盟内的点连到联盟外的点的边权),更新距离。

    实现:邻接矩阵 邻接表+优先队列

    时间复杂度:O(n2) & O(m log n)

    【别人说邻接表的是O(m log n),还是O(m+n)(??),可我用的是邻接表但并不那么觉得......既然这个算法几乎用不到,我就不深究了。然后我之后发现求SP最短路的Dijkstra 迪杰斯特拉算法除了“更新距离”那里不一样,其他代码都是一模一样的!⊙o⊙ 所以优化后的内容可以参考我的另外一篇的博文了。就是这个:关于最短路径问题(图论)

    应用:稠密图(Dense Graph, 由于主要看点数)

    注意——由于用到了邻接表的last[]和a[].next,所以要建双向边。

    代码如下——(无优化的)

     1 #include<cstdio>
     2 #include<cstdlib>
     3 #include<cstring>
     4 #include<iostream>
     5 #include<algorithm>
     6 using namespace std;
     7 
     8 const int N=55,M=3010,D=110;
     9 int n,m,len;
    10 struct edge
    11 {
    12     int x,y,d,next;
    13     edge() {}
    14     edge(int x,int y,int d):x(x),y(y),d(d) {}
    15 }a[M];
    16 int dis[N],vis[N],last[N];
    17 
    18 int mmin(int x,int y) {return x<y?x:y;}
    19 void ins(int x,int y,int d)
    20 {
    21     a[++len]=edge(x,y,d);
    22     a[len].next=last[x],last[x]=len;
    23 }
    24 int Prim()
    25 {
    26     int i,j,k,ans=0;
    27     memset(vis,0,sizeof(vis));
    28     memset(dis,63,sizeof(dis));//点到联盟的距离
    29     dis[1]=0;//candidate
    30     for (i=1;i<=n;i++)//每次选一个到联盟距离最小的vertices顶点
    31     {
    32       int p=0;
    33       for (j=1;j<=n;j++)
    34         if (!vis[j] && dis[j]<dis[p]) p=j;
    35       ans+=dis[p];
    36       dis[p]=0,vis[p]=1;
    37       for (k=last[p];k;k=a[k].next)//调整
    38       {
    39         int y=a[k].y;
    40         dis[y]=mmin(dis[y],a[k].d);
    41       }
    42     }
    43     return ans;
    44 }
    45 int main()
    46 {
    47     int i,x,y,d;
    48     while (scanf("%d",&n)!=EOF && n)
    49     {
    50       scanf("%d",&m);
    51       memset(last,0,sizeof(last));
    52       len=0;
    53       for (i=1;i<=m;i++)
    54       {
    55         scanf("%d%d%d",&x,&y,&d);
    56         ins(x,y,d),ins(y,x,d);
    57       }
    58       m*=2;
    59       printf("%d
    ",Prim());      
    60     }
    61     return 0;
    62 }
    Prim 邻接表

    还有一个模版题:【uva 1395】Slim Span(图论--最小生成树+结构体快速赋值 模版题)

  • 相关阅读:
    工厂方法和抽象工厂
    waterMarkTextBox
    button hot key 热键
    wpf 双击行。。获得行信息
    update comboBox
    WPF标准控件模板查看程序(文件里面)
    Sp EF输出 临时表
    tree view
    Ubuntu 常用命令
    ESP8266 开发记录
  • 原文地址:https://www.cnblogs.com/konjak/p/6021865.html
Copyright © 2020-2023  润新知