• 最小生成树(Prim普利姆算法、Kruskal克鲁斯卡尔算法)


    朴素版prim用于稠密图  堆优化版prim与Kruskal用于稀疏图 

    堆优化版prim太麻烦 不用学 直接用克鲁斯卡尔算法代替 

     

    普里姆算法Prim算法),图论中的一种算法,可在加权连通图里搜索最小生成树

    意即由此算法搜索到的边子集所构成的树中,不但包括了连通图里的所有顶点(Vertex ),且其所有边的权值之和亦为最小。在某些场合,普里姆算法又被称为DJP算法、亚尔尼克算法或普里姆-亚尔尼克算法。

    👉详细解析加保存路径版👈

    1. #include<bits/stdc++.h>
    2. using namespace std;
    3. const int N=510;
    4. int n,m;
    5. int g[N][N];//存放两条边之间的权值
    6. int dist[N];//存放某一点到连通部分的距离
    7. bool st[N];//节点是否被加入到生成树
    8. int prim(){
    9. memset(dist ,0x3f,sizeof dist);//任意一点到集合的距离初始化为无穷大
    10. dist[1]=0;//去第一个点作为起点 如果存在 最后每个点都要连接 所以取哪个点都可以
    11. int res=0;//存放权值之和
    12. for(int i=0;i<n;i++){//每次循环选出一个数加入生成树
    13. int t=-1;
    14. for(int j=1;j<=n;j++){//把每个节点都判断一次
    15. if(!st[j]&&(t==-1||dist[t]>dist[j]))//如果不在树中且到树的距离最短 就选择该点
    16. t=j;
    17. }
    18. if(dist[t]==0x3f3f3f3f) return 0x3f3f3f3f;//如果存在孤立点 直接return
    19. res+=dist[t];//把选中的到树最短距离的边加入到结果中
    20. st[t]=true;
    21. //法一 直接从1开始 方便写
    22. // for(int j=1;j<=n;j++){
    23. // dist[j]=min(dist[j],g[t][j]);//更新生成树外的节点到生成树的距离
    24. // }
    25. // 法二 实际不需更新已经确定过的点
    26. for(int j=1;j<=n;j++){
    27. if(dist[j]>g[t][j]&&!st[j]){
    28. dist[j]=g[t][j];
    29. }
    30. }
    31. }
    32. return res;
    33. }
    34. int main(){
    35. scanf("%d%d",&n,&m);
    36. memset(g,0x3f,sizeof g);//任意两点间的距离初始为无穷大
    37. while(m--){
    38. int a,b,c;
    39. scanf("%d%d%d",&a,&b,&c);
    40. g[a][b]=g[b][a]=min(g[a][b],c);//有重边 所以取最小
    41. }
    42. int t=prim();
    43. if(t==0x3f3f3f3f) puts("impossible");
    44. else printf("%d\n",t);
    45. return 0;
    46. }

    克鲁斯卡尔(Kruskal)算法从另一途径求网的最小生成树。其基本思想是:假设连通网G=(V,E),令最小生成树的初始状态为只有n个顶点而无边的非连通图T=(V,{}),概述图中每个顶点自成一个连通分量。在E中选择代价最小的边,若该边依附的顶点分别在T中不同的连通分量上,则将此边加入到T中;否则,舍去此边而选择下一条代价最小的边。依此类推,直至T中所有顶点构成一个连通分量为止 

     

    👉 详解来这里👈

    1. #include<bits/stdc++.h>
    2. using namespace std;
    3. const int N=100010,M=200010;
    4. int p[N];
    5. int n,m;//n个点集合 m个边的集合
    6. struct Edge{
    7. int a,b,w;
    8. }edges[M];
    9. bool cmp(const Edge &x,const Edge &y){//类型为结构体名 不是数组名
    10. return x.w<y.w;//结构体中利用权值从小到大排序
    11. }
    12. //并查集的模板
    13. int find(int x){
    14. if(p[x]!=x) p[x]=find(p[x]);
    15. return p[x];
    16. }
    17. int kruskal(){
    18. sort(edges,edges+m,cmp);
    19. for(int i=1;i<=n;i++) p[i]=i;
    20. int res=0,cnt=0;//res用于存最终结果 cnt用于存加入了多少条边
    21. for(int i=0;i<m;i++){
    22. int a=edges[i].a,b=edges[i].b,w=edges[i].w;
    23. if(find(a)!=find(b)){//a、b不在一个集合中 连接a到b
    24. //如果在一个集合中 说明两点已经用另一种方式连接 继续连接a到b会形成环
    25. p[find(b)]=find(a);//让b的根节点的父节点等于a的根节点
    26. cnt++;
    27. res+=w;
    28. }
    29. }
    30. if(cnt<n-1) return 0x3f3f3f3f;
    31. return res;
    32. }
    33. int main(){
    34. scanf("%d%d",&n,&m);
    35. for(int i=0;i<m;i++){
    36. int a,b,w;
    37. scanf("%d%d%d",&a,&b,&w);
    38. edges[i]={a,b,w};//把值存入结构体
    39. }
    40. int t=kruskal();
    41. if(t==0x3f3f3f3f) puts("impossible");
    42. else printf("%d\n",t);
    43. return 0;
    44. }

  • 相关阅读:
    算启新程 智享未来 | 紫光展锐携手中国移动共创数智未来
    【算法题】1488. 避免洪水泛滥
    干货复盘 | 银行数智化转型十大趋势
    threejs 3D标注
    java加密,使用python解密 ,使用 pysm4 报 byte greater than 16的解决方法
    Spring Cloud Gateway 路由构建器的源码分析
    string类
    使用CrossOver 在Mac 运行Windows 软件|D3DMetal是什么技术,
    【蓝桥杯选拔赛真题43】python二进制位数 青少年组蓝桥杯python 选拔赛STEMA比赛真题解析
    C++~类和对象总结(万字大总结,值得收藏)
  • 原文地址:https://blog.csdn.net/weixin_53515812/article/details/127423621