zoukankan      html  css  js  c++  java
  • 模板——最小生成树prim算法&&向前星理解

    通过最小生成树(prim)和最短路径优化引出的向前星存图,时至今日才彻底明白了。。

    head[i]存储的是父节点为i引出的最后一条边的编号

    next负责把head[i]也就是i作为父节点的所有边连接起来,next也是存的编号

    在所存的edge结构体中,只有w是保存边的值,而u是保存的子节点。

    这样设置的话,由head[i]就可以引出所有与i相关的边和点,

    显而易见,这样的存放方法空间+时间复杂度双优化,比邻接矩阵是优化多了。。

    然后就是prim算法,

    最小生成树的一种算法,适用于稠密图,因为是以点更新的,正好与之前的克鲁斯卡尔算法互补了,

    不过代码比k长,思路也难一些,大致和迪杰差不多,也用了dis数组,目测也就是更新dis值的时候不同(其实很不同,就形式差不多而已)

    下面附上代码,借鉴某位luogu大神的题解,真的很简洁明了了,在luogu上比 k 快了大概一倍240+ms。

    其他优化用了快读+re。

     1 #include <iostream>
     2 #include <string>
     3 #include <cstdio>
     4 #include <cstring>
     5 #include <queue>
     6 #define maxn 5002
     7 #define maxm 200001
     8 #define inf 9999
     9 #define re register
    10 
    11 using namespace std;
    12 
    13 int n,m,cnt,sum=0,k=0;
    14 int a,b,c;
    15 int dis[maxn],head[maxn],vis[maxn];
    16 
    17 typedef pair <int,int> pii;
    18 priority_queue <pii,vector<pii>,greater<pii> > q;
    19 
    20 struct Edge
    21 {
    22     int w,next,v;//w权值,v子节点 
    23 }edge[maxm*2];
    24 inline int read()  
    25 {  
    26     char ch;  
    27     int a=0;  
    28     while(!(((ch=getchar())>='0')&&(ch<='9')));  
    29     a*=10;a+=ch-'0';  
    30     while(((ch=getchar())>='0')&&(ch<='9'))a*=10,a+=ch-'0';  
    31     return a;  
    32 }
    33 void add(int u,int v,int w)
    34 {
    35     edge[++cnt].v=v;
    36     edge[cnt].w=w;
    37     edge[cnt].next =head[u];
    38     head[u]=cnt; 
    39 }
    40 
    41 void prim()
    42 {
    43     dis[1]=0;
    44     q.push(make_pair(0,1));
    45     while(!q.empty()&&k<n)
    46     {
    47         int d=q.top().first,u=q.top().second;//first 最小值,second 位置  
    48         q.pop();
    49         if(vis[u])continue;
    50         k++;
    51         sum+=d;
    52         vis[u]=1;
    53         for(re int i=head[u];i!=-1;i=edge[i].next )
    54         {
    55             if((edge[i].w<dis[edge[i].v]))
    56             {
    57                 dis[edge[i].v]=edge[i].w;
    58                 q.push(make_pair(dis[edge[i].v],edge[i].v)) ;
    59             }
    60         }
    61     } 
    62 }
    63 
    64 int main()
    65 {
    66     memset(head,-1,sizeof(head));
    67     memset(dis,inf,sizeof(dis));
    68     n=read();
    69     m=read();
    70     for(re int i=1;i<=m;i++)
    71     {
    72         a=read();b=read();c=read();
    73         add(a,b,c);
    74         add(b,a,c);
    75     }
    76     prim();
    77     if(k==n)printf("%d",sum);
    78     else  cout<<"orz";
    79     return 0;
    80 }
    ———————————————————————————————— 执笔饰年华,一笑叹天涯。逢春即润物,生当得潇洒。
  • 相关阅读:
    如何解决虚拟机频繁分离和附加磁盘导致的识别错误
    创建基于 AFS 的 Docker 容器卷
    使用 docker-machine 管理 Azure 容器虚拟机
    SSH 无法启动的原因分析及解决方法
    Azure 经典模式中虚拟机证书指纹的生成和作用
    远程桌面到 Ubuntu 虚拟机
    Azure Linux 虚拟机常见导致无法远程的操作
    Azure Linux 虚机上配置 RAID 的常见问题及解决方案
    使用 Azure CLI 在 Azure China Cloud 云平台上手动部署一套 Cloud Foundry
    数据库设计(六)第二范式(2NF)?
  • 原文地址:https://www.cnblogs.com/SuperGoodGame/p/9072746.html
Copyright © 2011-2022 走看看