求最小生成树相关例题题解

一.前言

求最小生成树常用的两种算法:prim算法和kruskal算法,之前我已经总结过prim算法的相关知识和使用方法(详细可以看这篇博客),而kruskal算法比较简单,更好操作(主要通过并查集和排序),所以在这里我就不总结了。如果有需要可以自行到网上学习(可以看看这篇博客)。

接下来我会总结最近写的几道求最小生成树的相关例题,(其中大多数用到kruskal算法,就当弥补一下),如果有需要以后会总结kruskal算法相关知识。


二.P1991 无线通讯网

https://www.luogu.com.cn/problem/P1991

题目描述

国防部计划用无线网络连接若干个边防哨所。2 种不同的通讯技术用来搭建无线网络;

每个边防哨所都要配备无线电收发器;有一些哨所还可以增配卫星电话。

任意两个配备了一条卫星电话线路的哨所(两边都有卫星电话)均可以通话,无论他们相距多远。而只通过无线电收发器通话的哨所之间的距离不能超过 D,这是受收发器的功率限制。收发器的功率越高,通话距离 D 会更远,但同时价格也会更贵。

收发器需要统一购买和安装,所以全部哨所只能选择安装一种型号的收发器。换句话说,每一对哨所之间的通话距离都是同一个 D。你的任务是确定收发器必须的最小通话距离 D,使得每一对哨所之间至少有一条通话路径(直接的或者间接的)。

输入格式

第一行,22 个整数 S 和 P,S 表示可安装的卫星电话的哨所数,P 表示边防哨所的数量。

接下里 P 行,每行两个整数 x,y 描述一个哨所的平面坐标 (x,y),以 km 为单位。

输出格式

第一行,11 个实数 D,表示无线电收发器的最小传输距离,精确到小数点后两位。

输入输出样例

输入 #1复制

2 4
0 100
0 300
0 600
150 750

输出 #1复制

212.13

说明/提示

数据范围及约定

  • 对于 20% 的数据:P=2,S=1;
  • 对于另外 20% 的数据:P=4,S=2;
  • 对于100% 的数据保证:1≤S≤100,S<P≤500,0≤x,y≤10000。

 这道题就是最小生成树的类型题,这里只要注意一下两点点间距离,将它们表示出来,作为边的权值就可以了,所以通过该函数实现

double length(int x1, int y1,int x2, int y2)
{return sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
}

完整代码

#include<bits/stdc++.h>
using namespace std;
#define N 1000005
int s, p, n, num;
double ans;
int a[N], b[N], pre[N];      //pre数组实现并查集
struct node {int x, y;double dis;
}f[N];                     //结构体数组存储各个点的信息以及距离bool cmp(node x, node y)
{return x.dis < y.dis;
}                           //sort内部比较函数,根据dis升序排列double length(int x1, int y1,int x2, int y2)      //计算两点间距离
{return sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
}int find(int x)                 //并查集,查操作
{if (pre[x] == x)return x;return pre[x] = find(pre[x]);
}void k()                         //kruskal核心代码段
{for (int i = 1; i <= n; i++) {int w = find(f[i].x);int v = find(f[i].y);if (w != v)             //如果不联通{pre[w] = v;         //将两个集合联通ans = f[i].dis;     //边权之和num++;             if (num >= p - s)   //退出条件,找到最小生成树{printf("%.2lf\n", ans);return ;}}}
}
int main()
{cin >> s >> p;for (int i = 1; i <= p; i++) {     //pre数组初始化为自己pre[i] = i;}for (int i = 1; i <= p; i++) {  //任意两点将距离,存图cin >> a[i] >> b[i];for (int j = 1; j < i; j++) {f[++n].x = i;f[n].y = j;f[n].dis = length(a[i], b[i], a[j], b[j]);}}sort(f + 1,f + 1 + n, cmp);      //根据dis降序排列k();return 0;
}


  

三.P2121 拆地毯

 https://www.luogu.com.cn/problem/P2121

题目背景

还记得 NOIP 2011 提高组 Day1 中的铺地毯吗?时光飞逝,光阴荏苒,三年过去了。组织者精心准备的颁奖典礼早已结束,留下的则是被人们踩过的地毯。请你来解决类似于铺地毯的另一个问题。

题目描述

会场上有 n 个关键区域,不同的关键区域由 m 条无向地毯彼此连接。每条地毯可由三个整数 u、v、w 表示,其中 u 和 v 为地毯连接的两个关键区域编号,w 为这条地毯的美丽度。

由于颁奖典礼已经结束,铺过的地毯不得不拆除。为了贯彻勤俭节约的原则,组织者被要求只能保留至多 K 条地毯,且保留的地毯构成的图中,任意可互相到达的两点间只能有一种方式互相到达。换言之,组织者要求新图中不能有环。现在组织者求助你,想请你帮忙算出这至多 K 条地毯的美丽度之和最大为多少。

输入格式

第一行包含三个正整数 n、m、K。

接下来 m 行中每行包含三个正整数 u、v、w。

输出格式

只包含一个正整数,表示这 K 条地毯的美丽度之和的最大值。

输入输出样例

输入 #1复制

5 4 3
1 2 10
1 3 9
2 3 7
4 5 3

输出 #1复制

22

说明/提示

选择第 1、2、4 条地毯,美丽度之和为 10 + 9 + 3 = 22。

若选择第 1、2、3 条地毯,虽然美丽度之和可以达到 10 + 9 + 7 = 26,但这将导致关键区域 1、2、3 构成一个环,这是题目中不允许的。

1<=n,m,k<=100000

 这道题也是典型的生成树问题,但这里不是最小生成树,而是求最大生成树,其实解决方法是一样的,只不过在排序的时候用降序排列就可以了

#include<bits/stdc++.h>
using namespace std;
#define N 1000005
int n, m, k, ans, sum;
int pre[N];               //pre数组,并查集
struct node {int u, v, w;
}f[N];                 //结构体数组存图bool cmp(node x, node y)
{return x.w > y.w;
}                        //根据边的降序排列int find(int x)          //并查集,查操作
{if (pre[x] == x)return x;return pre[x] = find(pre[x]);
}void kru()                 //kruskal核心代码段,一样的操作不多赘述
{for (int i = 1; i <= m; i++) {int x = find(f[i].u);int y = find(f[i].v);if (x != y){pre[x] = y;sum += f[i].w;ans++;}if (ans == k)            //退出条件,这里格外要注意退出条件,经常会出错{cout << sum << endl;return;}}
}
int main()
{cin >> n >> m >> k;for (int i = 1; i <= m; i++) {cin >> f[i].u >> f[i].v >> f[i].w;}for (int i = 1; i <= n; i++)pre[i] = i;                 //pre数组初始化sort(f + 1, f + m + 1, cmp);    //根据边降序排列kru();return 0;
}


四. P1194 买礼物

 https://www.luogu.com.cn/problem/P1194

题目描述

又到了一年一度的明明生日了,明明想要买 B 样东西,巧的是,这 B 样东西价格都是 A 元。

但是,商店老板说最近有促销活动,也就是:

如果你买了第 I 样东西,再买第 J 样,那么就可以只花KI,J​ 元,更巧的是,KI,J​ 竟然等于 KJ,I​。

现在明明想知道,他最少要花多少钱。

输入格式

第一行两个整数,A,B。

接下来 B 行,每行 B 个数,第 I 行第 J 个为 KI,J​。

我们保证 KI,J​=KJ,I​ 并且 KI,I​=0。

特别的,如果KI,J​=0,那么表示这两样东西之间不会导致优惠。

注意 KI,J​ 可能大于 A。

输出格式

一个整数,为最小要花的钱数。

输入输出样例

输入 #1复制

1 1
0

输出 #1复制

1

输入 #2复制

3 3
0 2 4
2 0 2
4 2 0

输出 #2复制

7

说明/提示

样例解释 2。

先买第 2 样东西,花费 3 元,接下来因为优惠,买 1,3 样都只要 2 元,共 7 元。

(同时满足多个“优惠”的时候,聪明的明明当然不会选择用 4 元买剩下那件,而选择用 22 元。)

数据规模

对于 30% 的数据,1≤B≤10。

对于 100% 的数据,01≤B≤500,0≤A,KI,J​≤1000。

2018.7.25新添数据一组

这道题和前面题目的不同之处在于,这里题目没有给我们直接边让我们存图,他这里是类似邻接矩阵的形式,我们要做的就是转换成我们熟悉的边存图,这里我们就通过两重循环将点和边存入结构体数组中,同时完了方便使用,我们从0出发,将初始价格a存入0到n的边中。

#include<bits/stdc++.h>
using namespace std;
#define N 1000005
int n, m, k, ans, sum, s;
int pre[N];           //一样的pre数组
struct node {int u, v, w;
}f[N];               //一样的结构体数组存图bool cmp(node x, node y)
{return x.w < y.w;
}                    //一样的比较函数int find(int x)      //一样的并查集,操作
{if (pre[x] == x)return x;return pre[x] = find(pre[x]);
}void kru()             //一样的kruskal核心代码段
{for (int i = 1; i <= ans; i++){int x = find(f[i].u);int y = find(f[i].v);if (x != y){pre[x] = y;sum += f[i].w;s++;}if (s == m) {        //一样的退出条件cout << sum << endl;return;}}
}
int main()
{cin >> n >> m;for (int i = 1; i <= m; i++) {       //重点来了,将边一一存入for (int j = 1; j <= m; j++) {  int a;cin >> a;if (a != 0) {ans++;               //这里就不根据题目来说了,就根据图来理解f[ans].u = i;        //起始点f[ans].v = j;        //终止点f[ans].w = a;        //边}}}for (int i = 1; i <= m; i++) {   //从0开始,存入最开始按原价买东西的情况ans++;f[ans].u = 0;f[ans].v = i;f[ans].w = n;}for (int i = 1; i <= m; i++)pre[i] = i;sort(f+1, f +1+ ans, cmp);      //根据w升序排列kru();return 0;
}


五.P2872 [USACO07DEC] Building Roads S

https://www.luogu.com.cn/problem/P2872

题目描述

Farmer John had just acquired several new farms! He wants to connect the farms with roads so that he can travel from any farm to any other farm via a sequence of roads; roads already connect some of the farms.

Each of the N (1 ≤ N ≤ 1,000) farms (conveniently numbered 1..N) is represented by a position (Xi, Yi) on the plane (0 ≤ Xi ≤ 1,000,000; 0 ≤ Yi ≤ 1,000,000). Given the preexisting M roads (1 ≤ M ≤ 1,000) as pairs of connected farms, help Farmer John determine the smallest length of additional roads he must build to connect all his farms.

给定 n 个点的坐标,第 i 个点的坐标为 (xi​,yi​),这 n 个点编号为 1 到 n。给定 m 条边,第 i 条边连接第 ui​ 个点和第 vi​ 个点。现在要求你添加一些边,并且能使得任意一点都可以连通其他所有点。求添加的边的总长度的最小值。

输入格式

* Line 1: Two space-separated integers: N and M

* Lines 2..N+1: Two space-separated integers: Xi and Yi

* Lines N+2..N+M+2: Two space-separated integers: i and j, indicating that there is already a road connecting the farm i and farm j.

第一行两个整数 n,m 代表点数与边数。
接下来 n 行每行两个整数 xi​,yi​ 代表第 i 个点的坐标。
接下来 m 行每行两个整数 ui​,vi​ 代表第 i 条边连接第 ui​ 个点和第 vi​ 个点。

输出格式

* Line 1: Smallest length of additional roads required to connect all farms, printed without rounding to two decimal places. Be sure to calculate distances as 64-bit floating point numbers.

一行一个实数代表添加的边的最小长度,要求保留两位小数,为了避免误差, 请用 6464 位实型变量进行计算。

输入输出样例

输入 #1复制

4 1
1 1
3 1
2 3
4 3
1 4

输出 #1复制

4.00

说明/提示

数据规模与约定

对于 100% 的整数,1≤n,m≤1000,1≤xi​,yi​≤106,1≤ui​,vi​≤n。

说明

Translated by 一只书虫仔。

 这题和第一题很像,其实代码也差不多一样,到这里我们发现其实大体操作都是一致的,所以这里我就直接给代码了。

#include <cmath>
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
#define N 5000100
int pre[N], xx[N], yy[N], n, m, cnt, sum;
double ans;
struct node {                    //重复的地方我就不写了int x, y;double dis;
}f[N];void add(int x, int y, double z)    //通过函数存边,都一样
{f[++cnt].x = x;f[cnt].y = y;f[cnt].dis = z;
}double d(int x, int y)          //求两点间距离,即边
{return (double)(sqrt((double)(xx[x] - xx[y]) * (xx[x] - xx[y]) + (double)(yy[x] - yy[y]) * (yy[x] - yy[y])));
}bool cmp(node x, node y)
{if (x.dis == y.dis)return x.x < y.x;return x.dis < y.dis;
}int find(int x)
{if (pre[x] == x)return x;return pre[x] = find(pre[x]);
}void kruskal()
{for (int i = 1; i <= cnt; i++) {int dx = find(f[i].x);int dy = find(f[i].y);if (dx != dy){pre[dx] = dy;sum++;ans += f[i].dis;}}
}
int main()
{cin >> n >> m;for (int i = 1; i <= n; i++) {cin >> xx[i] >> yy[i];}for (int i = 1; i <= n; i++) {pre[i] = i;}for (int i = 1; i <= n; i++) {         for (int j = i + 1; j <= n; j++) {double k = d(i, j);add(i, j, k);}}for (int i = 1; i <= m; i++) {     //已经连接的两点,其边相当于0int c, d;cin >> c >> d;add(c, d, 0.0);}sort(f + 1, f + cnt + 1, cmp);kruskal();printf("%.2lf\n", ans);return 0;
}


通过以上几个使用kruskal算法求最小生成树的例题分析,我们不难发现,通过kruskal算法不仅代码固定,而且比较简单,容易理解。

我们也可以通过prim算法来完成以上的例题,如果有需要我也可以用prim算法重新写一遍。

 OK,本次关于求最小生成树例题分析就结束了,如果对于本篇总结有疑问的欢迎讨论,同时如果有错误或者待修改完善的地方,也希望能够指出,我一定会及时改正,~QVQ~

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

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

相关文章

【深度学习】使用tensorflow实现VGG19网络

【深度学习】使用tensorflow实现VGG19网络 本文章向大家介绍【深度学习】使用tensorflow实现VGG19网络&#xff0c;主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项&#xff0c;具有一定的参考价值&#xff0c;需要的朋友可以参考一下。 VGG网络与AlexNet类似…

wayland(xdg_wm_base) + egl + opengles——dma_buf 作为纹理数据源(五)

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、EGL dma_buf import 相关的数据结构和函数1. EGLImageKHR2. eglCreateImageKHR()3. glEGLImageTargetTexture2DOES()二、egl 中 import dma_buf 作为纹理的代码实例1. egl_wayland_dmabuf_…

Why Not Http?

游戏服务器开发主要是基于socket&#xff0c;或者websocket&#xff0c;很少采用http&#xff08;可能有部分非常轻量级的服务器选择http&#xff09;。这是什么原因呢&#xff1f;我们先来看看socket与http之间的区别。 socket与http之间的区别 socket与http对比 sockethttpT…

【c++】list 模拟

> 作者简介&#xff1a;დ旧言~&#xff0c;目前大二&#xff0c;现在学习Java&#xff0c;c&#xff0c;c&#xff0c;Python等 > 座右铭&#xff1a;松树千年终是朽&#xff0c;槿花一日自为荣。 > 目标&#xff1a;能手撕list模拟 > 毒鸡汤&#xff1a;不为模糊…

红队ATKCK|红日靶场Write-Up(附下载链接)

网络拓扑图 下载地址 在线下载&#xff1a; http://vulnstack.qiyuanxuetang.net/vuln/detail/2/ 百度网盘 链接&#xff1a;https://pan.baidu.com/s/1nlAZAuvni3EefAy1SGiA-Q?pwdh1e5 提取码&#xff1a;h1e5 环境搭建 通过上述图片&#xff0c;web服务器vm1既能用于外…

学习Android的第十三天

目录 Android TextClock 文本时钟控件 TextClock 控件主要属性和方法 简单的 TextClock 参考文档 Android AnalogClock 控件 AnalogClock 属性 Android Chronometer 计时器 Chronometer 属性 Chronometer 主要方法 范例&#xff1a; 完整的计时器 范例&#xff1a; …

Rust 学习笔记 - Hello world

前言 本文将讲解如何完成一个 Rust 项目的开发流程&#xff0c;从编写 “Hello, World!” 开始&#xff0c;到使用 Cargo 管理和运行项目。 编写 Hello world 开始一个新项目很简单&#xff0c;首先&#xff0c;创建一个包含 main.rs 文件的 hello_world 文件夹&#xff0c;…

基于Doris构建亿级数据实时数据分析系统

转载至我的博客 https://www.infrastack.cn &#xff0c;公众号&#xff1a;架构成长指南 背景 随着公司业务快速发展&#xff0c;对业务数据进行增长分析的需求越来越迫切&#xff0c;与此同时我们的业务数据量也在快速激增、每天的数据新增量大概在30w 左右&#xff0c;一年…

BUUCTF misc 专题(47)[SWPU2019]神奇的二维码

下载附件&#xff0c;得到一张二维码图片&#xff0c;并用工具扫描&#xff08;因为图片违规了&#xff0c;所以就不放了哈。工具的话&#xff0c;一般的二维码扫描都可以&#xff09; swpuctf{flag_is_not_here}&#xff0c;&#xff08;刚开始出了点小差错对不住各位师傅&am…

代码随想录第32天|● 122.买卖股票的最佳时机II ● 55. 跳跃游戏 ● 45.跳跃游戏II

文章目录 买卖股票思路一&#xff1a;贪心代码&#xff1a; 思路&#xff1a;动态规划代码&#xff1a; 跳跃游戏思路&#xff1a;贪心找最大范围代码&#xff1a; 跳跃游戏②思路&#xff1a;代码&#xff1a; 方法二&#xff1a;处理方法一的特殊情况 买卖股票 思路一&#x…

C++类和对象-多态->多态的基本语法、多态的原理剖析、纯虚函数和抽象类、虚析构和纯虚析构

#include<iostream> using namespace std; //多态 //动物类 class Animal { public: //Speak函数就是虚函数 //函数前面加上virtual关键字&#xff0c;变成虚函数&#xff0c;那么编译器在编译的时候就不能确定函数调用了。 virtual void speak() { …

论全人类大脑潜在联系的可能性与现实意义

随着科技和神经科学研究的深入&#xff0c;越来越多的理论与实践表明&#xff0c;尽管人的大脑在物理形态上各自独立&#xff0c;但通过思维、情感、信息交流等多种方式&#xff0c;全人类的大脑之间存在着广泛的、潜在的联系。本文旨在探讨这种普遍联系的可能性及其对人类社会…

鸿蒙(HarmonyOS)项目方舟框架(ArkUI)之NavRouter组件

鸿蒙&#xff08;HarmonyOS&#xff09;项目方舟框架&#xff08;ArkUI&#xff09;之NavRouter组件 一、操作环境 操作系统: Windows 10 专业版、IDE:DevEco Studio 3.1、SDK:HarmonyOS 3.1 二、NavRouter组件 导航组件&#xff0c;默认提供点击响应处理&#xff0c;不需要…

微信公众号扫码登录

1.设计 我们采用的是个人号登录方式&#xff0c;这样拿不到我们的userInfo用户信息&#xff0c;然后我们将用户发来的消息&#xff08;xml消息体&#xff09;中的FromUser作为我们唯一的openId 整体流程: 1.用户扫码公众号码&#xff0c;然后发一条消息&#xff1a;验证码&…

2.13日学习打卡----初学RocketMQ(四)

2.13日学习打卡 目录&#xff1a; 2.13日学习打卡一.RocketMQ之Java ClassDefaultMQProducer类DefaultMQPushConsumer类Message类MessageExt类 二.RocketMQ 消费幂消费过程幂等消费速度慢的处理方式 三.RocketMQ 集群服务集群特点单master模式多master模式多master多Slave模式-…

C语言希尔排序详解!!!速过

目录 希尔排序是什么&#xff1f; 关于时间复杂度 希尔排序的源代码 希尔排序源代码的详解 希尔排序是什么&#xff1f; 之前我们说了三个排序&#xff08;插入排序&#xff0c;选择排序&#xff0c;冒泡排序&#xff09;有需要的铁铁可以去看看之前的讲解。 但因为之前的…

基于Python的信息加密解密网站设计与实现【源码+论文+演示视频+包运行成功】

博主介绍&#xff1a;✌csdn特邀作者、博客专家、java领域优质创作者、博客之星&#xff0c;擅长Java、微信小程序、Python、Android等技术&#xff0c;专注于Java、Python等技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; …

CSS 圆形的时钟秒针状的手柄绕中心点旋转的效果

<template><!-- 创建一个装载自定义加载动画的容器 --><view class="cloader"><!-- 定义加载动画主体部分 --><view class="clface"><!-- 定义类似秒针形状的小圆盘 --><view class="clsface"><!-…

docker (五)-docker存储-数据持久化

将数据存储在容器中&#xff0c;一旦容器被删除&#xff0c;数据也会被删除。同时也会使容器变得越来越大&#xff0c;不方便恢复和迁移。 将数据存储到容器之外&#xff0c;这样删除容器也不会丢失数据。一旦容器故障&#xff0c;我们可以重新创建一个容器&#xff0c;将数据挂…

Spring Boot与Kafka集成教程

当然可以&#xff0c;这里为您提供一个简化版的Spring Boot与Kafka集成教程&#xff1a; 新建Spring Boot项目 使用Spring Initializr或您喜欢的IDE&#xff08;如IntelliJ IDEA, Eclipse等&#xff09;新建一个Spring Boot项目。 添加依赖 在项目的pom.xml文件中&#xff0c;…