公路修建(洛谷P1265)

题目描述

某国有 n 个城市,它们互相之间没有公路相通,因此交通十分不便。为解决这一“行路难”的问题,政府决定修建公路。修建公路的任务由各城市共同完成。

修建工程分若干轮完成。在每一轮中,每个城市选择一个与它最近的城市,申请修建通往该城市的公路。政府负责审批这些申请以决定是否同意修建。

政府审批的规则如下:

  1. 如果两个或以上城市申请修建同一条公路,则让它们共同修建;
  2. 如果三个或以上的城市申请修建的公路成环。如下图,A 申请修建公路 AB,B 申请修建公路 BC,C 申请修建公路 CA。则政府将否决其中最短的一条公路的修建申请;
  3. 其他情况的申请一律同意。

一轮修建结束后,可能会有若干城市可以通过公路直接或间接相连。这些可以互相连通的城市即组成“城市联盟”。在下一轮修建中,每个“城市联盟”将被看作一个城市,发挥一个城市的作用。

当所有城市被组合成一个“城市联盟”时,修建工程也就完成了。

你的任务是根据城市的分布和前面讲到的规则,计算出将要修建的公路总长度。

输入格式

第一行一个整数 n,表示城市的数量。(n≤5000)

以下 n 行,每行两个整数 x 和 y,表示一个城市的坐标。(−106≤x,y≤106)

输出格式

一个实数,四舍五入保留两位小数,表示公路总长。(保证有唯一解)

输入输出样例

输入 #1复制运行

4 0 0 1 2 -1 2 0 4

输出 #1复制运行

6.47

说明/提示

修建的公路如图所示:

Prim 算法的隐式图应用

1. 题目背景与分析

题目模型:

给定平面上N个点的坐标 (x, y),这些点之间任意两个都可以直接相连,连接的代价是它们之间的欧几里得距离。要求将所有点连通,且总代价最小。

题目陷阱解析:

题目描述中提到了“每轮选择最近城市申请”、“成环否决最短边”等复杂的规则。其实,这些规则描述的过程,本质上就是Borůvka算法或Kruskal 算法构造最小生成树的过程。

无论描述多么花哨,这道题的核心任务非常明确:求完全图的最小生成树 (MST)。

2. 算法选型:Prim vs Kruskal

在做这道题时,算法的选择至关重要:

  • 数据规模:N<=5000。

  • 图的性质:这是一个完全图(任意两点间都有边)。边数 M=N*(N-1)/2约等于1.25*10^7。

对比分析

  1. Kruskal算法

    • 复杂度:O(M log M)。

    • 计算量:1.25*10^7*log(10^7)约等于3*10^8,有超时风险

    • 空间风险:存储10^7条边需要大量内存,极易 MLE (超内存)

  2. Prim 算法 (朴素版)

    • 复杂度:O(N^2)。

    • 计算量:5000^2 = 2.5*10^7,稳过

    • 空间优势:不需要把边存下来,只需要存储N个点的坐标。

结论:本题只能用 Prim算法,且必须采用不存边的隐式图方式。

3. 核心逻辑:隐式图Prim

由于边数太多,我们无法预先计算好所有边存入邻接矩阵。我们采取“随用随算”的策略:

  1. 距离计算:当Prim算法需要用到节点i和节点j的距离时,利用勾股定理sqrt(x_i-x_j)^2 + (y_i-y_j)^2现场计算。

  2. 流程

    • 初始化dis数组为无穷大。

    • 循环N次,每次寻找一个距离当前生成树集合最近的点p。

    • 将p加入集合,累加结果。

    • 关键点:用点p的坐标去尝试更新所有其他未入队点j的dis[j]

4. 完整代码实现

//prim+不存图,边权直接随时计算 #include <iostream> #include <cstring>//memset #include <cmath>//对应pow using namespace std; int x; double dis[5100];//每座城市到起点的距离 struct node{ double x;//横坐标 double y;//纵坐标 }n[5100];//保存所有城市坐标 const double inf=1e16; double sum;//最小生成树长度(公路总长度) int vis[5100];//标记每个城市是否加入城市联盟 void prim(int s){ dis[s]=0;//起点到自己距离为0 //要把所有x座城市都连接起来,每次找还未加入城市联盟且 //距离集合(城市联盟)最近的城市 for(int i=1;i<=x;i++){ int p=0; for(int j=1;j<=x;j++){ //每次找还未加入城市联盟且距离集合(城市联盟)最近的城市 if(vis[j]==0 && dis[p]>dis[j]){ p=j; } } //如果已经无城市可以加入城市联盟 就退出 if(p==0 || dis[p]>1e16) break; vis[p]=1;//否则就标记加入联盟 sum+=dis[p]; //然后用p点去更新所有未加入联盟的点到联盟的距离(因为边可以自己加) for(int j=1;j<=x;j++){ //如果j点经p点到达城市联盟比原本到达城市联盟的距离小 //就更新该距离 double juli=sqrt(pow(n[j].x-n[p].x,2)+pow(n[j].y-n[p].y,2));//j点到p点的距离 if(vis[j]==0 && dis[j]>juli){ dis[j]=juli; } } } } int main(){ cin>>x;//x座城市 for(int i=0;i<=x;i++) dis[i]=1e17;//初始化每个城市到起点距离为无穷 for(int i=1;i<=x;i++){ cin>>n[i].x>>n[i].y; } prim(1);//因为保证有唯一解 所以从任何一个点进去都可以 printf("%.2lf",sum); return 0; }

5. 易错点总结

  1. 数据类型与精度

    • 坐标和距离计算必须全程使用double。虽然坐标10^6平方后在long long范围内,但在开根号 (sqrt) 后变成了浮点数。

    • 输出时请严格按照题目要求使用printf("%.2lf",sum)fixed<< setprecision(2)

  2. 无穷大的设定与比较(重中之重)

    • 数值设定:两点间最大距离约2.8*10^6,INF建议设为1e17或更大,保证远超实际距离。

    • 初始化陷阱绝对不能使用memset(dis, 0x3f, ...)0x3f是针对int的位操作技巧,作用于double会导致数据变成极小的乱码。必须使用for循环手动赋值dis[i]=1e17

    • 判定方式:在判断“是否找到了有效点”或“是否连通”时,不要使用==(如if(dis[p]==INF))。由于浮点数运算存在微小误差,且为了逻辑安全,应当使用范围比较(如if(dis[p]>1e16))来判定是否为不可达状态。

  3. 内存限制

    千万不要尝试开double g[5000][5000]的邻接矩阵。这需要约 200MB 内存,大部 分题目限制 128MB,会导致MLE(内存超限)。必须使用本题解中的隐式图(现场计算距 离)方法。

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

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

相关文章

程序监控与异常防护-PART-Simulink-看门狗

程序监控与异常防护-PART-Simulink-看门狗程序监控与异常防护-PART-Simulink-看门狗 关键词 看门狗、程序监控、异常处理、Simulink、自动化控制一、问题分析:为什么需要看门狗 在自动化实验控制平台中,我们经常会遇…

LIDA 477 编码器位移/速度/加速度采集与转换-PART-LIDA 477-采集转换

LIDA 477 编码器位移/速度/加速度采集与转换-PART-LIDA 477-采集转换LIDA 477 编码器位移/速度/加速度采集与转换-PART-LIDA 477-采集转换 关键字:LIDA 477、Hidenhain、磁姗尺、编码器、位移、速度、加速度、Simulin…

1121

编程练习

软件升级回退报告

一、引言为提升软件系统性能、优化现有功能并修复已知问题&#xff0c;本团队于[升级实施日期]对[软件名称]系统开展了版本升级工作&#xff0c;计划将系统从[原版本号]升级至[目标版本号]。升级后&#xff0c;系统出现[简要说明核心问题&#xff0c;如&#xff1a;关键功能异常…

SQL Server数据库

数据库按照特定的数据结构来组织、存储和管理数据的集合作用高效地存储大量数据&#xff0c;并支持快速的查询、修改、删除等操作同时保证数据的安全性、完整性和一致性。一&#xff0c;创建主数据文件命令创建&#xff1a;create 修改&#xff1a;alt…

1124

编程练习

灵活用工系统开发全流程与案例分享【弹性用工解决方案|附源码】

一、模块设计分包商&#xff1a;税地注册公司&#xff0c;用于在当地申请有利的税收政策&#xff0c;是实际报税公司。 代理商&#xff1a;代理商可以邀请客户使用本平台&#xff0c;平台会给予代理商一定的服务费差价作为佣金。 客户&#xff1a;使用本平台进行工资发放的…

RocksDB 可直接运行的实战示例(多语言 + 完整安装 + 基础 CRUD + 事务 + 生产调优)

包含 C++(原生最优)、Java (企业级主流)、Python (快速上手) 三种最常用语言的完整代码,所有示例复制即可运行,涵盖你需要的「安装步骤、基础读写、事务操作、生产级调优参数」,优先级从高到低排序,按需选择即可。 核心前提:RocksDB 是嵌入式键值库,所有操作都是本地库调…

7月4日

今天:完成PTA部分练习,看了看大道至简,看了37页,明白原来完成一个项目是很难的,需要团队合作,就跟建筑一样,需要共同搭配合作,才能建造起来“房子” 明天:学习JAVA基础

VideoDownloadHelper视频下载助手终极指南:全网视频轻松保存

VideoDownloadHelper视频下载助手终极指南&#xff1a;全网视频轻松保存 【免费下载链接】VideoDownloadHelper Chrome Extension to Help Download Video for Some Video Sites. 项目地址: https://gitcode.com/gh_mirrors/vi/VideoDownloadHelper 想要将网页中的精彩视…

专业陪诊系统:守护银发健康

博主介绍&#xff1a; 所有项目都配有从入门到精通的安装教程&#xff0c;可二开&#xff0c;提供核心代码讲解&#xff0c;项目指导。 项目配有对应开发文档、解析等 项目都录了发布和功能操作演示视频&#xff1b; 项目的界面和功能都可以定制&#xff0c;包安装运行&#xf…

1126

编程练习

1013

JAVA练习,学习连接数据库

RocksDB 全面指南

RocksDB 是由 Meta&#xff08;原 Facebook&#xff09;开发的高性能嵌入式键值存储引擎&#xff0c;基于 Google LevelDB 改进而来&#xff0c;专为高吞吐量、低延迟的存储场景设计。它是一个 C 库而非独立数据库服务&#xff0c;可嵌入应用程序中提供持久化键值存储能力。一、…

7月5日

今天:完成10道编程题 明天:继续完成假期任务

1128

编程练习

Python 自动去除 代码中Debug 代码的终极方案(AST 实战)

在真实项目中&#xff0c;Debug 代码通常包括&#xff1a; print()logging.debug()logging.info()logger.debug()临时调试函数&#xff08;如 debug()、pprint()&#xff09;if DEBUG: 块 &#x1f449; 手动删除不现实&#xff0c;正则又极易误伤 &#x1f449; AST 是唯一靠谱…

亲测好用10个AI论文软件,专科生轻松搞定毕业论文!

亲测好用10个AI论文软件&#xff0c;专科生轻松搞定毕业论文&#xff01; AI工具&#xff0c;让论文写作不再难 对于专科生来说&#xff0c;毕业论文常常是人生中的一大挑战。从选题到撰写&#xff0c;再到查重降重&#xff0c;每一步都可能让人感到压力山大。而随着AI技术的不…