当前位置: 首页 > article >正文

PTA数据结构天梯赛L2-001:手把手教你用Dijkstra算法搞定双权值最短路径(附C语言完整代码)

PTA数据结构天梯赛L2-001双权值最短路径的Dijkstra算法实战解析在算法竞赛和数据结构课程中图论问题一直是考察重点和难点。面对PTA天梯赛L2-001这类需要同时考虑时间和距离两个权值的最短路径问题传统的单权值Dijkstra算法需要经过巧妙改造才能满足题目要求。本文将深入剖析如何基于经典Dijkstra算法进行扩展处理双权值条件下的最优路径选择问题。1. 问题分析与算法选择题目要求为一个天梯赛在线地图实现路径推荐功能需要输出两条路线最快到达路线和最短距离路线。当存在多条相同时间的路径时选择其中距离最短的当存在多条相同距离的路径时选择经过节点最少的。这种双权值条件下的路径优化问题需要我们对传统最短路径算法进行针对性改造。关键问题特征每条边有两个权值通过时间和路径长度路径选择需要考虑主次优化目标需要输出完整路径而不仅仅是路径长度算法选择对比算法类型适用场景本题适用性Dijkstra单源非负权最短路径高度适用需改造Floyd多源最短路径不必要计算冗余Bellman-Ford含负权边的最短路径不适用无负权边A*搜索启发式路径搜索适用但实现复杂基于上述分析选择Dijkstra算法作为基础进行改造是最优方案。我们需要实现两个版本的Dijkstra时间优先的最短路径算法时间相同时选择距离短的路径距离优先的最短路径算法距离相同时选择节点少的路径2. 数据结构设计与输入处理高效的数据结构是算法实现的基础。针对题目输入特点我们采用邻接矩阵存储图结构并使用结构体封装边属性。#define MAX 32767 // 表示无穷大的值 typedef struct { int length; // 路径长度 int time; // 通过时间 } Edge; int main() { int n, m; // n:节点数, m:边数 scanf(%d %d, n, m); // 初始化邻接矩阵 Edge graph[n][n]; for(int i 0; i n; i) { for(int j 0; j n; j) { graph[i][j].time MAX; graph[i][j].length MAX; } } // 读取边信息 for(int i 0; i m; i) { int x, y, one_way, len, t; scanf(%d %d %d %d %d, x, y, one_way, len, t); graph[x][y].length len; graph[x][y].time t; if(one_way 0) { // 双向边 graph[y][x].length len; graph[y][x].time t; } } int start, end; scanf(%d %d, start, end); // 后续算法处理... }输入处理注意事项明确边的单向/双向性质未连接的边初始化为MAX(无穷大)节点编号从0开始连续分布3. 双权值Dijkstra算法实现3.1 时间优先的最短路径算法在时间优先的算法中当两条路径时间相同时我们需要选择距离更短的路径。这需要在传统的Dijkstra算法中加入额外的判断条件。typedef struct { int prev_node; // 前驱节点 int total_time; // 累计时间 int total_length; // 累计距离 } TimePriorityPath; void dijkstra_time_priority(int start, int n, Edge graph[n][n], TimePriorityPath paths[n]) { int visited[n]; // 标记已确定最短路径的节点 for(int i 0; i n; i) { paths[i].prev_node -1; paths[i].total_time MAX; paths[i].total_length MAX; visited[i] 0; } paths[start].total_time 0; paths[start].total_length 0; for(int i 0; i n; i) { // 找出未访问节点中时间最短的 int min_node -1; int min_time MAX; for(int j 0; j n; j) { if(!visited[j] paths[j].total_time min_time) { min_time paths[j].total_time; min_node j; } } if(min_node -1) break; visited[min_node] 1; // 更新邻接节点 for(int j 0; j n; j) { if(graph[min_node][j].time MAX) { // 存在边 int new_time paths[min_node].total_time graph[min_node][j].time; int new_length paths[min_node].total_length graph[min_node][j].length; if(new_time paths[j].total_time) { paths[j].total_time new_time; paths[j].total_length new_length; paths[j].prev_node min_node; } else if(new_time paths[j].total_time new_length paths[j].total_length) { paths[j].total_length new_length; paths[j].prev_node min_node; } } } } }3.2 距离优先的最短路径算法在距离优先的算法中当两条路径距离相同时我们需要选择经过节点数更少的路径。这需要额外维护一个节点计数器。typedef struct { int prev_node; // 前驱节点 int total_length; // 累计距离 int node_count; // 路径节点数 } DistancePriorityPath; void dijkstra_distance_priority(int start, int n, Edge graph[n][n], DistancePriorityPath paths[n]) { int visited[n]; for(int i 0; i n; i) { paths[i].prev_node -1; paths[i].total_length MAX; paths[i].node_count 0; visited[i] 0; } paths[start].total_length 0; paths[start].node_count 1; for(int i 0; i n; i) { // 找出未访问节点中距离最短的 int min_node -1; int min_length MAX; for(int j 0; j n; j) { if(!visited[j] paths[j].total_length min_length) { min_length paths[j].total_length; min_node j; } } if(min_node -1) break; visited[min_node] 1; // 更新邻接节点 for(int j 0; j n; j) { if(graph[min_node][j].length MAX) { // 存在边 int new_length paths[min_node].total_length graph[min_node][j].length; int new_count paths[min_node].node_count 1; if(new_length paths[j].total_length) { paths[j].total_length new_length; paths[j].node_count new_count; paths[j].prev_node min_node; } else if(new_length paths[j].total_length new_count paths[j].node_count) { paths[j].node_count new_count; paths[j].prev_node min_node; } } } } }4. 路径重构与输出处理获得最短路径信息后我们需要从终点回溯到起点重构完整路径并按照题目要求的格式输出。void reconstruct_path(int start, int end, int prev_nodes[], int path[]) { int current end; int path_length 0; // 反向存储路径 while(current ! start) { path[path_length] current; current prev_nodes[current]; } path[path_length] start; // 现在path中存储的是end-...-start } void print_path(int path[], int length, const char* type, int value) { printf(%s %d: , type, value); for(int i length; i 0; i--) { printf(%d, path[i]); if(i 0) printf( ); } printf(\n); } int main() { // ...之前的输入处理代码... TimePriorityPath time_paths[n]; DistancePriorityPath dist_paths[n]; dijkstra_time_priority(start, n, graph, time_paths); dijkstra_distance_priority(start, n, graph, dist_paths); int time_route[n], dist_route[n]; reconstruct_path(start, end, time_paths, time_route); reconstruct_path(start, end, dist_paths, dist_route); // 计算路径长度 int time_len 0; while(time_route[time_len] ! start) time_len; int dist_len 0; while(dist_route[dist_len] ! start) dist_len; // 检查两条路径是否相同 int is_same 1; if(time_len ! dist_len) { is_same 0; } else { for(int i 0; i time_len; i) { if(time_route[i] ! dist_route[i]) { is_same 0; break; } } } // 按照题目要求格式输出 if(is_same) { printf(Time %d; Distance %d: , time_paths[end].total_time, dist_paths[end].total_length); for(int i time_len; i 0; i--) { printf(%d, time_route[i]); if(i 0) printf( ); } printf(\n); } else { print_path(time_route, time_len, Time, time_paths[end].total_time); print_path(dist_route, dist_len, Distance, dist_paths[end].total_length); } return 0; }5. 算法优化与性能分析对于节点数N≤500的规模上述O(N²)的Dijkstra实现已经足够。但在实际竞赛中我们可以考虑以下优化优先队列优化使用最小堆可以将时间复杂度优化到O(MlogN)其中M是边数。C语言中需要手动实现优先队列// 最小堆实现示例 typedef struct { int node; int value; // 时间或距离 } HeapNode; void heap_push(HeapNode heap[], int* size, HeapNode item) { heap[(*size)] item; int current *size; while(current 1 heap[current].value heap[current/2].value) { HeapNode temp heap[current]; heap[current] heap[current/2]; heap[current/2] temp; current / 2; } } HeapNode heap_pop(HeapNode heap[], int* size) { HeapNode result heap[1]; heap[1] heap[(*size)--]; int current 1; while(1) { int child current * 2; if(child *size) break; if(child 1 *size heap[child1].value heap[child].value) { child; } if(heap[current].value heap[child].value) break; HeapNode temp heap[current]; heap[current] heap[child]; heap[child] temp; current child; } return result; }空间优化技巧对于稀疏图使用邻接表而非邻接矩阵存储复用数组减少内存分配使用位运算压缩状态信息常见错误排查未正确初始化距离数组应初始化为INF忽略双向边的处理路径重构时未正确处理起点未考虑多条等价路径时的选择条件在实际竞赛中这类题目通常会设置严格的运行时间限制。对于N500的情况O(N²)的实现大约需要每次Dijkstra运算500² 250,000次操作两次Dijkstra500,000次操作在现代CPU上约需几毫秒完全在合理范围内

相关文章:

PTA数据结构天梯赛L2-001:手把手教你用Dijkstra算法搞定双权值最短路径(附C语言完整代码)

PTA数据结构天梯赛L2-001:双权值最短路径的Dijkstra算法实战解析 在算法竞赛和数据结构课程中,图论问题一直是考察重点和难点。面对PTA天梯赛L2-001这类需要同时考虑时间和距离两个权值的最短路径问题,传统的单权值Dijkstra算法需要经过巧妙…...

量子态重构技术QSDC:动态电路与机器学习结合

1. 量子态重构的技术挑战与QSDC框架概述 量子计算领域长期面临一个基础性难题:如何在电路运行过程中获取量子态的"快照"而不破坏其量子特性?传统量子态层析(QST)需要制备大量相同量子态副本进行测量,不仅效率…...

SPI接口技术解析与Keil开发实践指南

1. SPI接口技术解析与应用指南作为一名嵌入式开发工程师,我经常需要与各种外设进行通信,而SPI(Serial Peripheral Interface)无疑是最常用的串行通信协议之一。今天我想分享一些关于SPI接口的实用知识和资源,这些内容来…...

智能汽车人机交互与ADAS系统融合:架构、场景与工程实践

1. 项目概述:当驾驶舱的“大脑”与“眼睛”开始对话“集成人机交互和ADAS系统”——这个标题听起来像是一个纯粹的工程命题,但在我过去十多年的汽车电子开发经历中,我越来越深刻地体会到,这其实是一个关于“人、车、路”三者关系如…...

百万至千万级参与者的人类暴露组计划,准备好了没

化学暴露组学是否已为人类暴露组计划做好准备? 本文梳理了暴露组学的学科发展历程,阐明化学暴露组是解析环境致病因素、补齐健康研究短板的核心要素;总结了以高分辨质谱为核心的化学暴露组学在检测、采样与数据分析上的技术突破;…...

英雄联盟个性化工具LeaguePrank:安全自定义你的游戏身份

英雄联盟个性化工具LeaguePrank:安全自定义你的游戏身份 【免费下载链接】LeaguePrank 项目地址: https://gitcode.com/gh_mirrors/le/LeaguePrank LeaguePrank是一款基于英雄联盟官方LCU API开发的免费开源工具,允许玩家安全、合法地自定义游戏…...

保姆级教程:用Python脚本搞定YOLO生活垃圾数据集的划分与文件校验

Python实战:YOLO数据集自动化处理全流程指南 当你第一次拿到标注好的目标检测数据集时,是否曾被这些繁琐的准备工作困扰过?图片和标签文件散落在各处,需要手动划分训练集、验证集和测试集;文件命名不规范导致模型训练…...

用Tableau分析酒店数据:手把手教你做地区均价条形图和价格等级饼图

用Tableau分析酒店数据:手把手教你做地区均价条形图和价格等级饼图 酒店行业的数据分析往往需要快速洞察不同地区的价格分布和消费层级特征。作为全球领先的商业智能工具,Tableau能以直观的可视化方式呈现这些关键指标。本文将带你从零开始,用…...

别再复制粘贴了!手把手教你用C语言实现MODBUS CRC-16校验(附5种算法对比)

MODBUS CRC-16校验算法实战指南:从原理到最优实现选择 在工业自动化领域,MODBUS协议因其简单可靠而广泛应用,而CRC-16校验则是保障数据完整性的关键环节。许多开发者习惯直接复制网络上的校验代码,却常常遇到内存溢出、性能瓶颈或…...

告别命令行!用这个免费软件5分钟搞定Abaqus三维Voronoi泡沫模型

五分钟可视化构建Abaqus三维Voronoi泡沫模型:零代码解决方案全指南 在材料科学与工程仿真领域,三维Voronoi泡沫结构的建模一直是学术研究和工业应用的热点。这种仿生多孔结构因其优异的力学性能和轻量化特性,被广泛应用于缓冲材料、骨科植入物…...

手把手教你打造个人语音锁:基于PyTorch声纹识别项目,从环境搭建到GUI应用部署全流程

从零构建智能声纹锁:PyTorch工程化实战指南 当生物识别技术逐渐渗透日常生活,声纹识别正以其非接触、高便捷的特性成为身份认证的新宠。不同于指纹或人脸识别需要专用硬件支持,声纹识别仅需普通麦克风即可实现高精度身份验证。本文将带您完整…...

废水污染源在线监测管理平台方案

某企业从事染整加工生产,属于环境监管重点单位,安装有废水自动处理系统,监控因子包括PH值、化学需氧量、氨氮、总氮等。但在某次巡查工作时发现,化学需氧量远远超过排放标准,但涉事企业却未上报排放超标的情况。因此要…...

告别手动排版:用docx2tex将Word文档智能转换为LaTeX

告别手动排版:用docx2tex将Word文档智能转换为LaTeX 【免费下载链接】docx2tex Converts Microsoft Word docx to LaTeX 项目地址: https://gitcode.com/gh_mirrors/do/docx2tex 还在为论文排版而烦恼吗?每次从Word转换到LaTeX都要重新调整公式、…...

B站视频下载终极指南:3分钟掌握无水印高清下载技巧

B站视频下载终极指南:3分钟掌握无水印高清下载技巧 【免费下载链接】BiliDownload B站视频下载工具 项目地址: https://gitcode.com/gh_mirrors/bil/BiliDownload 你是否曾经想要保存B站上的精彩视频,却发现下载过程复杂繁琐?或者需要…...

Windows权限终极指南:5个场景掌握TrustedInstaller权限提升

Windows权限终极指南:5个场景掌握TrustedInstaller权限提升 【免费下载链接】RunAsTI Launch processes with TrustedInstaller privilege 项目地址: https://gitcode.com/gh_mirrors/ru/RunAsTI 当你面对Windows系统那些"拒绝访问"的提示时&#…...

GEE数据流转实战:如何用Google Drive和Assets搭建你的遥感数据处理流水线

GEE数据流转实战:构建云端遥感数据处理流水线 当遥感数据处理遇上云计算平台,一场关于效率的革命正在悄然发生。Google Earth Engine(GEE)作为全球领先的地理空间分析平台,与Google Drive和Assets的深度整合&#xff0…...

5分钟掌握Pearcleaner:macOS深度清理的终极免费方案

5分钟掌握Pearcleaner:macOS深度清理的终极免费方案 【免费下载链接】Pearcleaner A free, source-available and fair-code licensed mac app cleaner 项目地址: https://gitcode.com/gh_mirrors/pe/Pearcleaner 您是否曾为macOS上卸载应用后残留的配置文件…...

别再死记硬背公式了!用VHDL和Quartus II手把手教你玩转一位全加器(附完整源码与仿真)

从零实现数字逻辑:用VHDL在Quartus II中构建全加器的完整指南 当第一次接触数字逻辑设计时,那些抽象的真值表和逻辑表达式常常让人望而生畏。作为一名曾经同样困惑的工程师,我深刻理解初学者面对理论知识与实际工程实现之间的鸿沟。本文将带你…...

04. 骨架:后端分层架构与 TypeScript 类型系统实战

写在前面: 很多 GIS 开发者在写后端时,容易陷入“脚本思维”:一个文件几千行,数据库查询、业务逻辑、接口响应全混在一起。刚开始跑得快,但随着功能增加,代码会变成一团难以维护的“意大利面”。 在 light-mvt-server 中,我们坚持采用企业级的分层架构。今天,我们将深入…...

精准识别胡椒成熟度!YOLO-AVCA-CBAMNet 让智慧农业更高效

点击蓝字 关注我们 关注并星标 从此不迷路 计算机视觉研究院 公众号ID|计算机视觉研究院 学习群|扫码在主页获取加入方式 https://pmc.ncbi.nlm.nih.gov/articles/PMC12830288/ 计算机视觉研究院专栏 Column of Computer Vision Institute 本文提出YOLO-…...

国产工控机替代实战:从性能、成本到选型,核心场景落地指南

1. 国产替代的临界点:从“能用”到“好用”的质变在工业控制、金融交易、能源调度这些对稳定性和性能有严苛要求的领域,进口电脑设备,尤其是那些搭载英特尔至强处理器、运行Windows或特定Unix系统的工控机和工作站,曾经是唯一可靠…...

北京昌平浇筑阁楼测评:天顺诚达施工优但服务待提升,适合这类

本次测评聚焦于北京昌平区浇筑阁楼领域,旨在为对该服务感兴趣的人群提供客观、真实的数据和信息,帮助大家了解各相关企业的实际情况。参与本次测评的企业为北京天顺诚达建筑工程有限公司。需要声明的是,本次测评均基于真实数据与体验&#xf…...

AndroidCupsPrint:构建企业级Android打印服务架构的技术实践

AndroidCupsPrint:构建企业级Android打印服务架构的技术实践 【免费下载链接】AndroidCupsPrint Port of cups4j to Android. Allows wireless printing from any Android device to any CUPS-enabled print server or network printer. 项目地址: https://gitcod…...

Fast-GitHub:智能网络优化架构解析与分布式加速方案

Fast-GitHub:智能网络优化架构解析与分布式加速方案 【免费下载链接】Fast-GitHub 国内Github下载很慢,用上了这个插件后,下载速度嗖嗖嗖的~! 项目地址: https://gitcode.com/gh_mirrors/fa/Fast-GitHub 在国内开发者面临G…...

RT-Thread开发者大会技术解析:从RTOS内核到AIoT平台实战指南

1. 项目概述:一场国产嵌入式技术的年度盛会 2021年的RT-Thread开发者大会,对于当时国内嵌入式软件圈的从业者来说,绝对是一个绕不开的关键节点。那一年,整个行业正处在一个微妙的转折期:一方面,芯片供应链…...

小红书无水印下载终极指南:如何用XHS-Downloader快速保存优质内容

小红书无水印下载终极指南:如何用XHS-Downloader快速保存优质内容 【免费下载链接】XHS-Downloader 小红书(XiaoHongShu、RedNote)链接提取/作品采集工具:提取账号发布、收藏、点赞、专辑作品链接;提取搜索结果作品、用…...

从“能上传”到“可信可用”:如何用 Python 设计一个安全、可靠、可扩展的文件上传服务?

从“能上传”到“可信可用”:如何用 Python 设计一个安全、可靠、可扩展的文件上传服务? 文件上传服务看似简单:用户点一下按钮,文件传到服务器,返回一个 URL。可真正进入生产环境后,你会发现它不是一个“保…...

基于YOLO+DeepSeek的病虫害检测与环境监测一体化解决方案

智慧农业智能云平台 定位:基于YOLODeepSeek的病虫害检测与环境监测一体化解决方案🌾 核心识别能力 • 支持作物:9种 作物 作物 作物 🌽 玉米 🌾 小麦 🌾 水稻 🍅 番茄 🥔 马铃薯 &am…...

自然语言处理进阶:用BERT实现文本相似度计算

在软件测试领域,文本相似度计算是一项极具实用价值的技术。它能助力测试人员高效完成重复用例排查、智能测试用例生成、用户反馈聚类等任务,大幅提升测试工作的效率与精准度。传统的文本相似度计算方法,如基于词频的TF-IDF、基于词向量的Word…...

如何一键清理Windows冗余驱动:Driver Store Explorer完全指南

如何一键清理Windows冗余驱动:Driver Store Explorer完全指南 【免费下载链接】DriverStoreExplorer Driver Store Explorer 项目地址: https://gitcode.com/gh_mirrors/dr/DriverStoreExplorer 你是否发现C盘空间不知不觉就满了?Windows系统在C:…...