最小生成树(Kruskal+Prim)

举报
Linux猿 发表于 2021/08/05 23:12:29 2021/08/05
【摘要】 最小生成树:       概念:在无向图中,连通且不含圈的图称为树。给定无向图 G =(V,E),连接 G 中所有点,且边集是 E 的子集的树称为 G 的生成树,而权值最小的生成树称为最小生成树(MST)。下面就介绍两个算法:Kruskal算法和Prim算法。     Kruskal算法 &...

最小生成树:

      概念:在无向图中,连通且不含圈的图称为树。给定无向图 G =(V,E),连接 G 中所有点,且边集是 E 的子集的树称为 G 的生成树,而权值最小的生成树称为最小生成树(MST)。下面就介绍两个算法:Kruskal算法和Prim算法。

    Kruskal算法

         算法描述:克鲁斯卡尔算法需要对图的边进行访问,所以克鲁斯卡尔算法的时间复杂度只和边又关系。

算法过程:

1.将图各边按照权值进行排序

2.将图遍历一次,找出权值最小的边,(条件:此次找出的边不能和已加入最小生成树集合的边构成环),若符合条件,则加入最小生成树的集合中。不符合条件则继续遍历图,寻找下一个最小权值的边。

3.递归重复步骤1,直到找出n-1条边为止(设图有n个结点,则最小生成树的边数应为n-1条),算法结束。得到的就是此图的最小生成树。

克鲁斯卡尔(Kruskal)算法因为只与边相关,则适合求稀疏图的最小生成树。

如图:

代码(HDU 1233题 还是畅通工程):


  
  1. #include<stdio.h>
  2. #include<algorithm>
  3. using namespace std;
  4. int n,m,ans;
  5. int father[105];//记录父亲节点,开始都指向自己
  6. struct zhang
  7. {
  8. int x,y,w;
  9. }t[5009];
  10. bool cmp(const zhang &a,const zhang &b)
  11. {
  12. return a.w < b.w ;//按权值从小到大排序
  13. }
  14. void kruskal()
  15. {
  16. int find(int x);
  17. int x,y,i;
  18. for(i=0;i<m;i++)
  19. {
  20. x=find(t[i].x);
  21. y=find(t[i].y);
  22. if(x!=y)
  23. {
  24. father[x]=y;
  25. ans+=t[i].w;
  26. }
  27. }
  28. }
  29. int find(int x)//查找父亲节点
  30. {
  31. if(father[x]!=x)
  32. x=find(father[x]);
  33. return x;
  34. }
  35. int main()
  36. {
  37. int i;
  38. while(scanf("%d",&n)!=EOF)
  39. {
  40. ans=0;
  41. if(n==0)
  42. break;
  43. m=n*(n-1)/2;
  44. for(i=1;i<=n;i++)
  45. father[i]=i;
  46. for(i=0;i<m;i++)
  47. scanf("%d%d%d",&t[i].x,&t[i].y,&t[i].w);
  48. sort(t,t+m,cmp);
  49. kruskal();
  50. printf("%d\n",ans);
  51. }
  52. return 0;
  53. }


  Prim算法        

       普里姆算法的基本思想:

      从图G={V,E}中的某一顶点U0出发,选择与它关联的具有最小权值的边(U0,v),将其顶点加入到生成树的顶点集合U中。以后每一步从一个顶点在U中,而另一个顶点不在U中的各条边中选择权值最小的边(u,v),把它的顶点加入到集合U中。如此继续下去,直到图中的所有顶点都加入到生成树顶点集合U中为止。

     算法描述:Prim算法需要对图的顶点进行访问,所以Prim算法的时间复杂度只和图中的顶点有关系,所以适合求稠密图的最小生成树。

任意指定一个顶点作为起始点,放在S中(一般选1点)。

每一步将最短的特殊边放入S中,需要n-1步,即可把所有的其他的点放入S中。算法结束。

如图:

代码(NOJ 502题 筹建工程):


  
  1. #include<stdio.h>
  2. #include<string.h>
  3. #define INF 9999999
  4. int ans,m,q;
  5. int vis[102],low[102],map[102][102];
  6. void prim()
  7. {
  8. int i,j,k;
  9. for(i=2;i<=m;i++)
  10. low[i]=map[1][i];
  11. vis[1]=1;
  12. q=1;
  13. for(i=2;i<=m;i++)
  14. {
  15. int x=1,min=INF;
  16. for(j=2;j<=m;j++)//寻找最小边
  17. if(!vis[j]&&low[j]<min)
  18. {
  19. x=j;
  20. min=low[j];
  21. }
  22. ans+=min;
  23. if(x==1)
  24. break;
  25. q++;
  26. vis[x]=1;//标记顶点
  27. for(k=2;k<=m;k++)
  28. if(!vis[k]&&low[k]>map[x][k])
  29. low[k]=map[x][k];
  30. }
  31. }
  32. int main()
  33. {
  34. int T,i,j,n,x,y,z;
  35. scanf("%d",&T);
  36. while(T--)
  37. {
  38. memset(vis,0,sizeof(vis));
  39. scanf("%d%d",&n,&m);
  40. for(i=1;i<=m;i++)
  41. for(j=1;j<=m;j++)
  42. if(i!=j)
  43. map[i][j]=INF;
  44. else
  45. map[i][j]=0;
  46. for(i=0;i<n;i++)
  47. {
  48. scanf("%d%d%d",&x,&y,&z);
  49. map[x][y]= map[y][x]=z;
  50. }
  51. ans=0;
  52. prim();
  53. if(q==m)
  54. printf("%d\n",ans);
  55. else
  56. printf("No solution\n");
  57. }
  58. return 0;
  59. }


 

 

 

 

   

          

文章来源: blog.csdn.net,作者:Linux猿,版权归原作者所有,如需转载,请联系作者。

原文链接:blog.csdn.net/nyist_zxp/article/details/9615003

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。