zoukankan      html  css  js  c++  java
  • [洛谷P3366] [模板] 最小生成树

    存个模板,顺便复习一下kruskal和prim。

    题目传送门

    kruskal

    稀疏图上表现更优。

    设点数为n,边数为m。

    复杂度:O(mlogm)。

    先对所有边按照边权排序,初始化并查集的信息。

    然后枚举每一条边,如果当前边的两个端点不在一个并查集里,就选上这条边。

    如果图不连通会造成选的边数小于n-1。

    如果成功生成了最小生成树,就会正好选n-1条边(树的性质)。

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 #include<queue>
     5 using namespace std;
     6 
     7 int n,m,cnt,ans;
     8 
     9 struct edge
    10 {
    11     int x,y,w;
    12 }e[200005];
    13 
    14 int f[5005];
    15 
    16 int findfa(int p)
    17 {
    18     if(p==f[p])return p;
    19     f[p]=findfa(f[p]);
    20     return f[p];
    21 }
    22 
    23 int cmp(edge q,edge r)
    24 {
    25     return q.w<r.w;
    26 }
    27 
    28 void kruskal()
    29 {
    30     sort(e+1,e+m+1,cmp);
    31     for(int i=1;i<=m;i++)
    32     {
    33         int fx=findfa(e[i].x);
    34         int fy=findfa(e[i].y);
    35         if(fx==fy)continue;
    36         ans+=e[i].w;
    37         cnt++;
    38         f[fx]=fy;
    39     }
    40 }
    41 
    42 int main()
    43 {
    44     scanf("%d%d",&n,&m);
    45     for(int i=1;i<=n;i++)f[i]=i;
    46     for(int i=1;i<=m;i++)
    47         scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].w);
    48     kruskal();
    49     if(cnt<n-1)printf("orz");
    50     else printf("%d",ans);
    51     return 0;
    52 }

    prim

    稠密图上表现更优。

    时间复杂度:O(nlogn+m)。

    算法很像dijkstra求最短路。

    只不过这个是维护某个点到已选的点组成的点集的距离,而不是到源点的距离。

    初始先随便选一个点,把这个点的距离设为0,剩下的点的距离设为0x3f3f3f3f。

    然后就很像dijkstra......

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 #include<queue>
     5 using namespace std;
     6 
     7 int n,m,cnt,ans;
     8 int hd[5005],nx[400005],to[400005],len[400005],ec;
     9 int dis[5005],v[5005];
    10 
    11 void edge(int af,int at,int ev)
    12 {
    13     to[++ec]=at;
    14     nx[ec]=hd[af];
    15     len[ec]=ev;
    16     hd[af]=ec;
    17 }
    18 
    19 struct data
    20 {
    21     int ps,ds;
    22     friend bool operator<(data q,data w)
    23     {
    24         return q.ds>w.ds;
    25     }
    26 };
    27 
    28 priority_queue<data>qq;
    29 
    30 void prim()
    31 {
    32     memset(dis,0x3f,sizeof(dis));
    33     dis[1]=0,cnt++;
    34     qq.push((data){1,0});
    35     while(!qq.empty()&&cnt<=n)
    36     {
    37         data p=qq.top();
    38         qq.pop();
    39         if(v[p.ps])continue;
    40         v[p.ps]=1;
    41         cnt++;
    42         ans+=p.ds;
    43         for(int i=hd[p.ps];i;i=nx[i])
    44         {
    45             if((dis[to[i]]>len[i])&&(!v[to[i]]))
    46             {
    47                 dis[to[i]]=len[i];
    48                 qq.push((data){to[i],dis[to[i]]});
    49             }
    50         }
    51     }
    52 }
    53 
    54 int main()
    55 {
    56     scanf("%d%d",&n,&m);
    57     for(int i=1;i<=m;i++)
    58     {
    59         int x,y,z;
    60         scanf("%d%d%d",&x,&y,&z);
    61         edge(x,y,z);
    62         edge(y,x,z);
    63     }
    64     prim();
    65     if(cnt<n)printf("orz");
    66     else printf("%d",ans);
    67     return 0;
    68 }
  • 相关阅读:
    大道至简第二篇阅读笔记
    大道至简第一篇阅读笔记
    冲刺第十天
    冲刺第九天
    冲刺第八天
    冲刺第七天
    用java构造一个带层次的文件目录遍历器
    用java进行简单的万年历编写
    delphi 图像处理 图像左旋右旋
    delphi 图像处理 图像放大缩小
  • 原文地址:https://www.cnblogs.com/cervusy/p/9756262.html
Copyright © 2011-2022 走看看