首页 > 其他分享 >最小生成树和次小生成树

最小生成树和次小生成树

时间:2023-10-08 11:55:53浏览次数:24  
标签:xm 最小 生成 fa second && first mx 树和次

OI-wiki Link

最小生成树,就是图上边权和最小的生成树。

令 \(n\) 为图上节点数,\(m\) 为图的边数。

$$\texttt{Kruskal}$$

克鲁斯卡尔算法,一种常见且方便好写的最小生成树算法,利用贪心的思想+并查集维护。

贪心就是按边权从小到大排序,依次处理。如果当前边的两个端点处于同一棵树内,那么就不能加这条边(否则会形成环,不满足生成树的要求),否则将这条边连起来。

判断两点是否处于同一棵树内,这不就是并查集所维护的吗?

排序:\(O(m\log m)\),并查集就看写的是什么了。空间复杂度:\(O(n+m)\)。

$$\texttt{Prim}$$

Prim 是另外一种常见且码量也不算很多的最小生成树算法,主要思想就是维护每个点到生成树内的点的最短距离,每次把距离最小的加入最小生成树。

加入距离最小的点,这个也可以用优先队列维护,但它复杂度并没有更优,常数也比 Kruskal 要大,所以一般非必要情况下不会写 Prim。

<iframe allowfullscreen="true" border="0" frameborder="no" framespacing="0" height="600," scrolling="no" src="//player.bilibili.com/player.html?aid=354646476&bvid=BV1dX4y1k7Ky&cid=1086621365&p=1" width="900,"> </iframe>

次小生成树

非严格次小生成树

令图的最小生成树为 \(T\),那么对于每条非树边 \((u,v,w)\),找到 \(T\) 中 \(u\) 到 \(v\) 路径上的边权最大的一条边,把它删掉,再加入 \((u,v,w)\),就可以得到一棵新的生成树,取这些新的生成树中边权之和最小的即可。

维护 \(u,v\) 路径上的边权最大值也很简单,首先预处理,然后每次倍增 LCA 即可。

严格次小生成树

观察原本的算法,为啥它是非严格的呢?因为可能这条路径上的最大值恰好等于 \(w\),此时边权之和没有改变,所以是非严格的。

解决方法也很简单,只要在维护最大值时顺便维护一个严格次大值,当最大值等于 \(w\) 时则用严格次大值来替换。

细节不少,D 了我至少一个小时。

struct MST {
  vector<pair<int, int>> g[N];
  int fa[N][25], mx[N][25][2], h[N];
  void Add (int x, int y, int z) {
    g[x].push_back({y, z}), g[y].push_back({x, z});
  }
  void MkTe (int x) {
    h[x]++;
    for (auto i : g[x]) {
      if (i.first != fa[x][0]) {
        fa[i.first][0] = x, mx[i.first][0][0] = i.second, mx[i.first][0][1] = -1, h[i.first] = h[x], MkTe(i.first);
      }
    }
  }
  void FAT () {
    for (int i = 0; i <= 20; i++) {
      mx[0][i][0] = mx[0][i][1] = -1;
    }
    for (int i = 1; i <= 20; i++) {
      for (int j = 1; j <= n; j++) {
        fa[j][i] = fa[fa[j][i - 1]][i - 1], mx[j][i][0] = mx[j][i - 1][0], mx[j][i][1] = mx[j][i - 1][1];
        if (mx[fa[j][i - 1]][i - 1][0] > mx[j][i][0]) {
          mx[j][i][1] = mx[j][i][0], mx[j][i][0] = mx[fa[j][i - 1]][i - 1][0];
        } else if (mx[fa[j][i - 1]][i - 1][0] < mx[j][i][0] && mx[fa[j][i - 1]][i - 1][0] > mx[j][i][1]) {
          mx[j][i][1] = mx[fa[j][i - 1]][i - 1][0];
        }
        if (mx[fa[j][i - 1]][i - 1][1] < mx[j][i][0] && mx[fa[j][i - 1]][i - 1][1] > mx[j][i][1]) {
          mx[j][i][1] = mx[fa[j][i - 1]][i - 1][1];
        }
      }
    }
  }
  pair<int, int> lca (int x, int y) {
    if (h[x] > h[y]) {
      swap(x, y);
    }
    pair<int, int> xm = {-1, -1};
    for (int i = 20; i >= 0; i--) {
      if ((h[y] - h[x]) >> i) {
        if (mx[y][i][0] > xm.first) {
          xm.second = xm.first, xm.first = mx[y][i][0];
        } else if (mx[y][i][0] < xm.first && mx[y][i][0] > xm.second) {
          xm.second = mx[y][i][0];
        }
        if (mx[y][i][1] < xm.first && mx[y][i][1] > xm.second) {
          xm.second = mx[y][i][1];
        }
        y = fa[y][i];
      }
    }
    if (x == y) {
      return xm;
    }
    for (int i = 20; i >= 0; i--) {
      if (fa[x][i] != fa[y][i]) {
        if (mx[y][i][0] > xm.first) {
          xm.second = xm.first, xm.first = mx[y][i][0];
        } else if (mx[y][i][0] < xm.first && mx[y][i][0] > xm.second) {
          xm.second = mx[y][i][0];
        }
        if (mx[y][i][1] < xm.first && mx[y][i][1] > xm.second) {
          xm.second = mx[y][i][1];
        }
        if (mx[x][i][0] > xm.first) {
          xm.second = xm.first, xm.first = mx[x][i][0];
        } else if (mx[x][i][0] < xm.first && mx[x][i][0] > xm.second) {
          xm.second = mx[x][i][0];
        }
        if (mx[x][i][1] < xm.first && mx[x][i][1] > xm.second) {
          xm.second = mx[x][i][1];
        }
        y = fa[y][i], x = fa[x][i];
      }
    }
    if (mx[y][0][0] > xm.first) {
      xm.second = xm.first, xm.first = mx[y][0][0];
    } else if (mx[y][0][0] < xm.first && mx[y][0][0] > xm.second) {
      xm.second = mx[y][0][0];
    }
    if (mx[y][0][1] < xm.first && mx[y][0][1] > xm.second) {
      xm.second = mx[y][0][1];
    }
    if (mx[x][0][0] > xm.first) {
      xm.second = xm.first, xm.first = mx[x][0][0];
    } else if (mx[x][0][0] < xm.first && mx[x][0][0] > xm.second) {
      xm.second = mx[x][0][0];
    }
    if (mx[x][0][1] < xm.first && mx[x][0][1] > xm.second) {
      xm.second = mx[x][0][1];
    }
    return xm;
  }
} mst;

标签:xm,最小,生成,fa,second,&&,first,mx,树和次
From: https://www.cnblogs.com/wnsyou-blog/p/17748451.html

相关文章

  • PHP生成word的三种方式
    最近工作遇到关于生成word的问题现在总结一下生成word的三种方法。btw:好像在博客园发表博客只要是标题带PHP的貌似点击量都不是很高(哥哥我标题还是带上PHP了),不知道为什么,估计博客园上net技术大牛比较多吧,如果把java,.net,php比作程序员的女友,那么java是Oracle门下的大家闺秀,.net微......
  • kernel如何根据dtb文件生成device tree
    kernel如何根据dtb文件生成devicetreedevicetreedtb文件中的内容会被内核组成了devicetree,整个tree上由两个数据结构组成:structdevice_node和structproperty。structdevice_node{ constchar*name; phandlephandle; constchar*full_name; structfwnode_handle......
  • Flask PIN码生成终端RCE
    来自[GYCTF2020]FlaskApp这道题确实不会,只能乖乖看wp做复现,但是学到了很牛逼的东西,一部分flask的SSTI注入知识和PIN码的生成机制。点进去就是base64的加解密程序,hint处有个提示,源码里有PIN。预期解应该是debug出pin码然后终端RCE。非预期解字符串拼接这里用的是字符串拼接......
  • vue2自定义指令实现el-dropdown下拉菜单项最小宽度等于内容宽度
    //在main.js添加Vue.directive('siem-dropdown',function(el,binding,vNode){letul=el.querySelector("ul")letuid=vNode.componentInstance._uid;//获取下拉菜单实例的uidletsiemDropdownClass=`siem-dropdown-${uid}`;ul.cla......
  • 【AI 模型】首个 Joy 模型诞生!!!全民生成 Joy 大片
    接上一篇文章“只要10秒,AI生成IP海报,解放双手”,这次是全网第一个“共享joy模型”,真的赚到了!经过这段时间无数次的探索、试错、实验,最终积累了非常多的训练经验,在不同IP角色的训练上实际上需要调试非常多的参数以及素材。本次成功完成了Joy的Lora模型,虽然在泛化以及场景上未来还......
  • 基于深度学习的图像生成与识别技术研究
    基于深度学习的图像生成与识别技术是人工智能领域中备受关注的研究领域之一。这些技术借助深度神经网络模型,具有出色的性能和广泛的应用,包括图像生成、图像识别、图像分割等。以下是关于这两个领域的研究方向和趋势:图像生成技术生成对抗网络(GANs):GANs是生成图像最引人注目......
  • .NET 使用 ZXing.Net 生成二维码,并识别
    .NET使用ZXing.Net生成二维码,并识别前言前面已经分享给很多创建二维码,条形码。。。等一系列的方式各有优缺点,暂时不做评价。今天推荐ZXing.Net。也是比较全面的一种方式,还支持解码.NET二维码生成库-QrCodeGenerator商业库--Spire.BarcodeThoughtWorks.QRCodeQRCoder......
  • 生成一个指数回归模型,以预测温度与其他变量的关系, 并给出模型的函数
    #导入所需的库importpandasaspdimportnumpyasnpimportmatplotlib.pyplotaspltimportseabornassnsfromsklearn.linear_modelimportLinearRegressionfromsklearn.metricsimportmean_squared_error,r2_score#指定支持中文的字体,例如SimHei或者Microsoft......
  • 如何科学地分析高中学生成绩
    科学地分析高中学生成绩需要综合考虑多个因素,包括学生个人素质、学习方法、学校教育环境等。以下是一个详细的分析过程,供参考:一、学生个人素质分析:1.学习态度和动机:分析学生对学习的态度和动机是否积极主动,是否具有持之以恒的学习动力以及是否具备学习的目标感。2.自我管理......
  • 为功耗分析生成仿真波形文件及RTL文件列表
    一、获取RTL文件列表RTL文件包括vhdl,v,sv三种文件,可以根据后缀获取工程内部所有文件夹,及子文件夹内部的相关文件。可以通过shell脚本实现该功能。1#!/bin/bash2######################################################################3##......