经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » C++ » 查看文章
【算法随笔】最小生成树
来源:cnblogs  作者:Ekretn  时间:2019/1/25 10:13:12  对本文有异议

最小生成树(MST):[洛谷模版传送门]

一个有 n 个结点的连通图的生成树是原图的极小连通子图,且包含原图中的所有 n 个结点,并且有保持图连通的最少的边。

——度娘百度百科

说白了就是给你一个图,把边权等都给你(特殊情况是相等的)。然后让这些节点全部都连成一颗树,问最小的代价是多少。

本篇blog会对kruskal算法进行详细讲解。其实是Prim掌握还不熟

kruskal算法是用的比较多的一类求最小生成树的算法。核心思想是贪心。程序要做的重要两步:

1.给边排序,比较的标准是边的权值,小的在前面。

2.开始从排序后开始枚举边,如果这条边的起点和终点已经联通,则不管,反之则加入。

为什么这个方法是对的呢?

请你思考一下:每个可以联通的点,因为已经排好了序,如果节点v还没有加入,现有一条(u,v)的边,肯定比其他到v的权值更小。

 

我们采取“逐个击破”的原则去做出这两步:

一.给边排序

 这里有两种方案可以让边进行快速排序(当然你要手写快排我也不拦你)

1.为sort函数传入第三个参数

有兴趣的同学可以看一下sort

如果有同学问:为什么有两个sort函数?

C++是支持函数重载的,只要参数个数和类型不同,都可以同时存在

然后我们可以定义一个compare函数(其实很复杂的,目前可以先这么理解)

然后我们传参进去,穿的是compare函数的地址。

  1. 1 bool cmp(Edge x,Edge y){return x.dis<y.dis;}
    2 sort(edge,edge+m,cmp);//注意这个地方cmp后面没有括号和参数!!!

这是第一种定义大小比较。

2.重载运算符'<'

在Edge的结构体内放上这样一行:

  1. bool operator <(const Edge A)const{
  2. return dis<A.dis;
  3. }//const修饰符不要忘了!!!

这个时候可以直接sort。

二.枚举边,看终点是否已经连接

 这个看上去很麻烦。。。判断联通是比较困难的,BFS和DFS都可以,但是——TLE会向你招手

那有没有一个比较简单易学的算法来实现呢?

我们发现:如果一个点和另一个点联通,他们之间是可以不管父亲儿子节点。

于是有同学想到了STL的容器set没错那个同学就是我

但是set太low了是错的。因为边排序后,生成(联通)每一条边并不一定相等。

所以我们需要一个高效简介的算法:并查集

我们只需要维护一个f数组,f[u]表示节点u的父亲。

再套一个函数find,用于找到u的最终祖先。

  1. 1 int find(int x){return f[x]==x?x:f[x]=find(f[x]);}//简洁
    3 f[v]=u;//让v的的父亲变成u

所以,我们以洛谷测试为例:

krusal的过程是这样的:

 

(1)ans+=2;

 

 (2)ans+=2;

 

 

 (3)ans+=3;

下面仍给出代码:

  1. 1 #include<bits/stdc++.h>
  2. 2 namespace Jason{
  3. 3 inline int scan(int &x){
  4. 4 int f=1;x=0;char s=getchar();
  5. 5 while(s<'0' || s>'9'){if(s=='-') f=-1;s=getchar();}
  6. 6 while(s>='0' && s<='9'){x=x*10+s-'0';s=getchar();}
  7. 7 x*=f;
  8. 8 return 1;//返回1说明读入正常
  9. 9 }
  10. 10 inline int print(int x){
  11. 11 if(x<0){putchar('-');x=-x;}
  12. 12 if(x>9)print(x/10);char s=x%10+'0';
  13. 13 putchar(s);
  14. 14 return 1;//返回1说明输出正确
  15. 15 }
  16. 16 }
  17. 17 using namespace std;
  18. 18 using namespace Jason;
  19. 19 const int maxn=5005;
  20. 20 const int maxm=200005;
  21. 21 struct Edge{
  22. 22 int s,t,dis;
  23. 23 bool operator <(const Edge A)const{
  24. 24 return dis<A.dis;
  25. 25 }
  26. 26 }edge[maxm<<1];
  27. 27 int n,m,tot=-1;
  28. 28 int f[maxn];
  29. 29 //-----------------------------------------------数据结构和读入输出优化
  30. 30 void init(){for(int i=1;i<=n;++i)f[i]=i;}
  31. 31 inline int find(int x){return f[x]==x?x:f[x]=find(f[x]);}
  32. 32 //-----------------------------------------------并查集相关函数
  33. 33 bool cmp(Edge x,Edge y){return x.dis<y.dis;}
  34. 34 void add(int u,int v,int w)
  35. 35 {
  36. 36 edge[++tot].s=u;
  37. 37 edge[tot].t=v;
  38. 38 edge[tot].dis=w;
  39. 39 }
  40. 40 int kruskal(){
  41. 41 int ans=0;
  42. 42 sort(edge,edge+m);
  43. 43 for(int i=0;i<m;++i)
  44. 44 {
  45. 45 int u=find(edge[i].s),v=find(edge[i].t);
  46. 46 if(u!=v)
  47. 47 ans+=edge[i].dis;
  48. 48 f[v]=u;
  49. 49 }
  50. 50 return ans;
  51. 51 }
  52. 52 int main()
  53. 53 {
  54. 54 scan(n),scan(m);
  55. 55 init();
  56. 56 for(int i=0,x,y,z;i<m;++i)scan(x),scan(y),scan(z),add(x,y,z);
  57. 57 int ans=kruskal();
  58. 58 print(ans);
  59. 59 putchar('\n');
  60. 60 return 0;
  61. 61 }

有一个动态算法可视网站[点我进入],里面有MST,Dijkstra,Bellman-Ford等算法,疯狂安利。

 

 

原文链接:http://www.cnblogs.com/JasonY1337357025/p/10318052.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号