鱼C论坛

 找回密码
 立即注册
查看: 2611|回复: 0

[学习笔记] 不详解模板--最小生成树 Kruskal 算法

[复制链接]
发表于 2018-10-21 21:54:32 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
最小生成树
  是由n个节点的连通图变化来的。这棵树满足如下条件:
    1、是原来图的子图(原来的图扣去了几条边)
    2、在保证图仍然连通的情况下,剩下的边权和是最小的
    3、满足树的性质
  最小生成树常用来解决这样的问题:
    有n个村庄,他们之间本没有路(走的人多了就有路了 逃ε=ε=ε=┏(゜ロ゜;)┛)。我们现在知道每两个村庄之间修路的费用,求最少的修路费用。要求修路后任意两个村庄均可到达。
Kruskal 算法
  很容易想到,1、我们希望取的边权(路费)要尽量小(贪心)。
        2、如果a和b之间修了一条路,b和c之间修了一条路,那么我们就不必再在a和c之间修路了(所以满足树的性质)。
  所以,我们从权值最小的边开始枚举(sort),将它连通的点标记为连通(放到同一个并查集中)。如果有两点已经连通(a->b->c 即视为a与c连通),跳过这条边,继续向后枚举。
  如果不连接较短边而通过更长的边连接,一定不会比连接更短边更优。。。
  关于并查集的知识,请。。。百度
  贪心算法请感性理解。。。(逃)
  不扯了,上代码:
  1. //自我感觉码风良好(滑稽)
  2. //应该比较易懂,变量名大都与含义对应,
  3. //本代码耗时比较多   
  4. //PS:AC是肯定能AC的(luogu P3366)
  5. //多说一句,这个题所有的点都连通。。。顺便标注一下易错点


  6. #include <cstdio>
  7. #include <algorithm>

  8. using namespace std;
  9. //Definition
  10. const int MAXN = 5005;
  11. const int MAXM = 400005;

  12. struct Edge {
  13.      int from, to, val;
  14. }edge[MAXM];

  15. int num_edge, n, m, ans;
  16. int x, y, z;
  17. int f[MAXN];

  18. inline void AddEdge(int from, int to, int val);
  19. inline int getfather(int x);
  20. inline void merge_set(int x, int y);
  21. bool comp(const Edge a, const Edge b);

  22. //main function
  23. int main() {
  24.      scanf("%d%d", &n, &m);        //注意取址符
  25.      for(int i = 1; i <= n; i++) f[i] = i;
  26.      for(int i = 0; i < m; i++) {
  27.          scanf("%d%d%d", &x, &y, &z);    //无向图    从x到y有一条长度为z的边
  28.          AddEdge(x, y, z);               //无向图
  29.          AddEdge(y, x, z);               //无向图   有向图请去掉这一句
  30.      }

  31.      sort(edge, edge + num_edge, comp);  //这很Kruskal QwQ  不要忘记std

  32.      for(int i = 0; i < num_edge; i++) {
  33.          int from = edge[i].from;
  34.          int to = edge[i].to;
  35.          int val = edge[i].val;
  36.          if(getfather(from) == getfather(to)) continue;  //这两点已经在同一个并查集中
  37.          merge_set(from, to);                 //合并from和to所在的集合
  38.          ans += val;
  39.      }
  40.      printf("%d", ans);
  41.      return 0;
  42. }


  43. inline void AddEdge(int from, int to, int val) {    //顾名思义,简单粗暴
  44.      edge[num_edge].from = from;
  45.      edge[num_edge].to = to;
  46.      edge[num_edge].val = val;
  47.      num_edge++;
  48. }


  49. inline int getfather(int x) {               //顾名思义
  50.      if(f[x] == x) return x;                 //路径压缩
  51.      f[x] = getfather(f[x]);
  52.      return f[x];
  53. }

  54. inline void merge_set(int x, int y) {       //合并两个并查集
  55.      int fx = getfather(x);                  //没有打按秩合并QwQ
  56.      int fy = getfather(y);
  57.      f[fx] = f[fy];                //不要把fx和fy打成x和y(我就这么干过)
  58. }

  59. bool comp(const Edge a, const Edge b) {
  60.      return (a.val < b.val);
  61. }
复制代码

小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-6-9 00:16

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表