每周算法:次小生成树

题目链接

秘密的牛奶运输

题目描述

农夫约翰要把他的牛奶运输到各个销售点。

运输过程中,可以先把牛奶运输到一些销售点,再由这些销售点分别运输到其他销售点。

运输的总距离越小,运输的成本也就越低。

低成本的运输是农夫约翰所希望的。

不过,他并不想让他的竞争对手知道他具体的运输方案,所以他希望采用费用第二小的运输方案而不是最小的。

现在请你帮忙找到该运输方案。

注意:

  • 如果两个方案至少有一条边不同,则我们认为是不同方案;
  • 费用第二小的方案在数值上一定要严格大于费用最小的方案;
  • 答案保证一定有解;

输入格式

第一行是两个整数 N , M N,M N,M,表示销售点数和交通线路数;

接下来 M M M 行每行 3 3 3 个整数 x , y , z x,y,z x,y,z,表示销售点 x x x 和销售点 y y y 之间存在线路,长度为 z z z

输出格式

输出费用第二小的运输方案的运输总距离。

样例 #1

样例输入 #1

4 4
1 2 100
2 4 200
2 3 250
3 4 100

样例输出 #1

450

提示

【数据范围】

1 ≤ N ≤ 500 1≤N≤500 1N500,
1 ≤ M ≤ 1 0 4 1≤M≤10^4 1M104,
1 ≤ z ≤ 1 0 9 1≤z≤10^9 1z109,
数据中可能包含重边。

算法思想

根据题目描述,求的是一棵严格次小生成树。所谓严格指的是该次小生成树的总边权严格大于最小生成树的边权之和。如果次小生成树的总边权大于等于最小生成树的边权之和,那么可以称为非严格次小生成树

要求次小生成树,可以先求最小生成树,然后枚举非树边(不在最小生成树中的边),尝试将该边加入树中,同时从树中去掉一条边,保证最终仍然是一棵树。统计所有这些树的边权之和的最小值就是次小生成树。如下图所示:在这里插入图片描述
该算法的基本思想如下:

  • 使用Kruskal算法求图中的最小生成树,边权之和 s u m sum sum;并标记每条边是否在最小生成树中;同时构建出最小生成树。
  • 预处理最小生成树中任意两点之间代价最大的边的边权 d 1 [ a , b ] d1[a,b] d1[a,b]和代价次大的边的边权 d 2 [ a , b ] d2[a, b] d2[a,b],便于将来用非树边去替换。
  • 依次枚举所有不在最小生成树中的边 a ↔ b a \leftrightarrow b ab,边权为 c c c。尝试用该边替换节点 a a a到节点 b b b的路径中的一条边,显然要选代价最大或者次大的那条边。
    • 如果 c > d 1 [ a , b ] c > d1[a,b] c>d1[a,b],可以用该边替换 a a a b b b路径中代价最大的那条边,替换之后的总权值为 s u m − d 1 [ a , b ] + c sum-d1[a,b]+c sumd1[a,b]+c
    • 否则如果 c < d 1 [ a , b ] c<d1[a,b] c<d1[a,b]并且 c > d 2 [ a , b ] c >d2[a,b] c>d2[a,b],可以用该边替换 a a a b b b路径中代价次大的那条边,替换后的总价值为 s u m − d 2 [ a , b ] + c sum-d2[a,b]+c sumd2[a,b]+c
  • 求所有替换之后总权值的最小值,就是次小生成树。

时间复杂度

Kruskal算法的时间复杂度为 O ( m l o g m ) O(mlogm) O(mlogm),预处理最小生成树中任意两点之间代价最大和次大的边的时间复杂度为 O ( n 2 ) O(n^2) O(n2)

代码实现

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 505, M = 1e4 + 5;
struct E {int a, b, c;bool f; //表示是否在最小生成树中bool operator < (const E &e) const { return c < e.c; }
}edge[M];
int n, m;
int p[N], d1[N][N], d2[N][N];
int h[N], e[M], w[M], ne[M], idx;
int find(int x)
{if(x != p[x]) p[x] = find(p[x]);return p[x];
}
void add(int a, int b, int c)  // 添加一条边a->b,边权为c
{e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx ++ ;
}//预处理生成树中u点到其它点之间所有边中边权最大值d1[u][v]和次大值d2[u][v]
void dfs(int u, int fa, int maxd1, int maxd2, int d1[], int d2[])
{d1[u] = maxd1, d2[u] = maxd2;for(int i = h[u]; ~ i; i = ne[i]){int v = e[i];if(v != fa) //避免往回搜索 {int t1 = maxd1, t2 = maxd2;if(w[i] > t1) t2 = t1, t1 = w[i];else if(w[i] < t1 && w[i] > t2) t2 = w[i];dfs(v, u, t1, t2, d1, d2);}}
}
int main()
{cin >> n >> m;for(int i = 0; i < m; i ++) cin >> edge[i].a >> edge[i].b >> edge[i].c;memset(h, -1, sizeof h);//最小生成树sort(edge, edge + m);for(int i = 1; i <= n; i ++) p[i] = i;LL sum = 0;for(int i = 0; i < m; i ++){int a = edge[i].a, b = edge[i].b, c = edge[i].c;int pa = find(a), pb = find(b);if(pa != pb){p[pa] = pb;sum += c;add(a, b, c), add(b, a, c); //构建最小生成树edge[i].f = true;}}//处理最小生成树种任意两点间所有边中边权的最大值和次大值,注意最大值和次大值初始化尽可能小for(int i = 1; i <= n; i ++) dfs(i, -1, -1e9, -1e9, d1[i], d2[i]);LL ans = 1e18;//枚举所有不在最小生成树中的边for(int i = 0; i < m; i ++){if(!edge[i].f) {int a = edge[i].a, b = edge[i].b, c = edge[i].c;//尝试边i替换a-b的路径中最大的一条边LL t = 1e18;if(c > d1[a][b]) t = sum - d1[a][b] + c;else if(c > d2[a][b]) t = sum - d2[a][b] + c;ans = min(ans, t);}}cout << ans << endl;return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/19590.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

react 动态form表单

需求在日常开发中反复写form 是一种低效的开发效率&#xff0c;布局而且还不同这就需要我们对其封装 为了简单明了看懂代码&#xff0c;我这里没有组件&#xff0c;都放在一起&#xff0c;简单抽离相信作为大佬的你&#xff0c;可以自己完成&#xff0c; 首先我们做动态form …

Gartner发布电信运营商应对持续变化的网络安全环境指南:现代云安全与网络安全的五大核心挑战

所有组织的云和网络都面临着高级威胁。作为网络安全的关键参与者&#xff0c;电信运营商的 CIO 需要了解行业面临的挑战&#xff0c;并了解应采用哪些解决方案来实现方法的现代化。 主要发现 电信运营商 (CSP) CIO 如果不能调整其安全策略来保护其环境&#xff0c;那么他们将会…

IDEA 中导入脚手架后该如何处理?

MySQL数据库创建啥的&#xff0c;没啥要说的&#xff01;自行配置即可&#xff01; 1.pom.xml文件&#xff0c;右键&#xff0c;add Maven Project …………&#xff08;将其添加为Maven&#xff09;【下述截图没有add Maven Project 是因为目前已经是Maven了&#xff01;&…

LNMP安装部署

yum -y install ncurses ncurses-devel bison cmake openssl-devel gcc gcc-c make 方法二

差旅游记|绵阳印象:与其羡慕他人,不如用力活好自己。

哈喽&#xff0c;你好啊&#xff0c;我是雷工&#xff01; 来绵阳之前同事就问: “雷工&#xff0c;能吃辣嘛&#xff1f;”。 “还行&#xff0c;能吃点辣。” “那你去了四川别说能吃点辣&#xff0c;那边的能吃点比跟你说的能吃点不太一样” 01 你好 今天打车&#xff0c;上…

「多客」圈子论坛社区交友系统开源版小程序源码|圈子社区系统

简述 社交圈子论坛系统是一种面向特定人群或特定话题的社交网络&#xff0c;它提供了用户之间交流、分享、讨论的平台。在这个系统中&#xff0c;用户可以创建、加入不同的圈子&#xff0c;圈子可以是基于兴趣、地域、职业等不同主题的。用户可以在圈子中发帖、评论、点赞等互…

抖音太可怕了,我卸载了

这两天刷短视频&#xff0c;上瘾了&#xff0c;太可怕了。 自己最近一直在研究短视频制作&#xff0c;所以下载了抖音&#xff0c;说实话&#xff0c;我之前手机上并没有抖音&#xff0c;一直在用B站。 用了两天抖音&#xff0c;我发现&#xff0c;这玩意比刷B站还容易上瘾啊…

Centos 7下的VulFocus靶场搭建详细教程

一、靶场介绍 自带 Flag 功能&#xff1a;每次启动 flag 都会自动更新&#xff0c;明确漏洞是否利用成功。带有计分功能。兼容 Vulhub、Vulapps 中所有漏洞镜像。 二、下载安装 下载 VMware 软件下载 centos镜像 三、Docker知识 学习链接&#xff1a;https://www.runoob.c…

chrome调试手机网页

前期准备 1、 PC端安装好chrmoe浏览器 2、 安卓手机安装好chrmoe浏览器 3、 数据线 原文地址&#xff1a;https://lengmo714.top/343880cb.html 手机打开调试模式 进入手机设置&#xff0c;找到开发者模式&#xff0c;然后启用USB调试 打开PC端chrome调试功能 1、点击chr…

【康耐视国产案例】AI视觉相机创新 加速商超物流数智化转型

连锁商超/零售店正面临着因消费者购物习惯改变等挑战&#xff0c;迎来了以新兴技术崛起而催生的数字化物流体系转型需求。物流行业与AI机器视觉的深度融合&#xff0c;解决了传统机器视觉识别速度慢、环境要求高、定制化部署耗时过多等痛点&#xff0c;大大提高了物流供应链的效…

GD32F470+lwip 丢包问题分析及解决

最近在用GD32和管理机之间用TCP协议开发一个功能&#xff0c;功能都没问题&#xff0c;后面跑大量发包时候的连续测试时&#xff0c;总是会出现偶发性的&#xff0c;大概几分钟到数十分钟的一次丢包。尽管在应用层做了超时机制&#xff0c;一旦超时就会重新建立socket链接并重新…

QT系列教程(6) 几种标准对话框

几种标准对话框 本文介绍几种标准对话框&#xff0c;都是Qt封装好的&#xff0c;我们先创建一个界面&#xff0c;添加几个按钮&#xff0c;然后分别在几个按钮的回调函数里添加创建不同对话框的逻辑 颜色对话框 颜色对话框用来选择颜色&#xff0c;创建后会显示各种颜色和透明…

ABB码垛机器人IRB260通讯板维修

ABB码垛机器人在现代制造业中发挥着重要作用&#xff0c;而机器人通讯板维修对于确保机器人的正常运行至关重要。 通讯板是ABB码垛机器人与控制系统之间进行数据传输的桥梁。它负责接收控制系统的指令&#xff0c;并将机器人的运行数据反馈给控制系统。如果通讯板出现故障&…

Qos基础

一、Qos概述 Qos是一个框架&#xff0c;解决服务质量&#xff0c;尽力而为模型&#xff0c;集成服务以及区分服务模型&#xff0c;流量分类与标识。 使用Qos是带宽不够。 每个接口有硬件队列和软件队列&#xff08;队列排满了就不会再排&#xff09;。 企业宽带一般都是上行和下…

WHAT - 用户登录系列(二)- 单点登录 SSO

目录 一、认证机制1.1 基于会话的认证&#xff08;Session-based Authentication&#xff09;1. 介绍2. 基本流程 1.2 JSON Web Tokens (JWT)1. 介绍2. jwt 组成3. 基本流程4. 阻止列表5. 刷新令牌 二、单点登录&#xff1a;SSO2.1 单系统登录2.2 SSO 介绍2.3 SSO 登录2.4 SSO …

使用jquery.mousewheel-3.0.6.pack.js时报错

基于1.12.4版本的jquery.min.js&#xff0c;在使用jquery.mousewheel-3.0.6.pack.js时报错了&#xff1a; 可以如下解决&#xff1a; addEventListener事件里要加上{ passive: false }&#xff0c;这样就可以在使用鼠标滚轮放大缩小图片时&#xff0c;就不会报上述的错误了。 …

解决docker容器: bash: ping: command not found, 并制作镜像

一. 出现原因 从 dockerhub 拉下来的镜像都是最轻量级的, 不会安装各种工具, 所以使用 ping, vim 等命令, 会出现 command not found 二. 解决方式 2.1 安装工具包 进入到一个正在运行的容器内部, 执行命令: apt-get update 之后会发现, 容器正在更新软件包, 不过最终会由…

水工建筑物荷载设计规范的技术关键点

遵循《水工建筑物荷载设计规范》的指引&#xff0c;水工建筑所承载的荷载依据其作用的时间变异性特征&#xff0c;可划分为永久作用荷载、可变作用荷载以及偶然作用荷载三个主要类别。 一、荷载分类及其特点 永久作用荷载&#xff1a;涉及建筑物自身的结构重量&#xff0c;以及…

主线程等待所有线程结束之后再执行

如何让主线程等待所有线程结束之后再执行 1、Future的机制&#xff0c;使用Future.get()阻塞等待结果&#xff08;Future&#xff0c;FutureTask&#xff09; 2、CountDownLatch同步工具类&#xff0c;此类的作用就是一个线程等待所有线程结束之后再执行 3、CompletableFuture …

音视频开发—FFmpeg播放YUV文件,YUV转换为JPEG操作

文章目录 1.使用命令行播放YUV数据1.1命令解析1.2参数说明 2.使用C语言实现将YUV数据转为JPEG图片格式2.1需求分析2.2读取YUV源文件2.3将YUV数据封装为AVFrame2.4将NV12 转换为YUV420平面格式2.5初始化MJPEG编码器2.6将YUV420P编码为JPEG2.7将编码数据写入图片文件2.8完整代码 …