1. 题目背景与需求分析地铁一日游问题来源于PTA团体程序设计天梯赛L3级别的一道图论算法题。题目模拟了魔都地铁的特殊计价规则和乘客的拍照行为要求我们计算从指定起点出发按照特定规则能够到达的所有站点。1.1 问题核心规则题目设定了几条关键规则计价规则起步价2元每超过K公里加1元不足K公里部分不计拍照规则对于相同车费的站点只选择距离最远的或线路末端站点出站拍照换乘规则允许任意换乘且不产生额外费用移动规则每次拍照后以上次拍照站点为新起点继续移动1.2 算法挑战点这道题的难点在于需要处理大规模图数据N≤200M≤1500要同时考虑最短路径和特定转移规则需要高效计算可达性Q≤200次查询在Java环境下有严格的时间和空间限制550ms64MB2. 解决方案设计2.1 整体算法框架我采用的解决方案包含以下关键步骤使用Floyd-Warshall算法预处理全源最短路径构建符合拍照规则的转移图使用BitSet优化的传递闭包计算可达性处理查询并输出结果2.2 数据结构选择static long[][] dist; // 存储最短距离 static BitSet[] can; // 存储可达性 static boolean[] isTerminal; // 标记线路末端站点选择这些数据结构的原因是long[][] dist需要存储200×20040000个距离值使用long防止溢出BitSet[] canBitSet能高效存储和操作可达性关系节省内存boolean[] isTerminal简单标记末端站点空间效率高3. 核心算法实现3.1 最短路径计算使用Floyd-Warshall算法预处理所有站点间的最短距离for (int k 1; k N; k) { for (int i 1; i N; i) { if (dist[i][k] INF) continue; for (int j 1; j N; j) { if (dist[i][j] dist[i][k] dist[k][j]) { dist[i][j] dist[i][k] dist[k][j]; } } } }时间复杂度O(N³)对于N200来说是可接受的200³8,000,000次操作。3.2 转移图构建根据拍照规则构建转移关系MapLong, Long fareMax new HashMap(); for (int j 1; j N; j) { if (i j || dist[i][j] INF) continue; long level dist[i][j] / K; fareMax.put(level, Math.max(fareMax.getOrDefault(level, -1L), dist[i][j])); } for (int j 1; j N; j) { if (i j || dist[i][j] INF) continue; long level dist[i][j] / K; if (dist[i][j] fareMax.get(level) || isTerminal[j]) { can[i].set(j); } }这里使用HashMap记录每个票价档位的最远距离然后设置转移关系。3.3 传递闭包计算使用BitSet优化传递闭包计算for (int k 1; k N; k) { for (int i 1; i N; i) { if (can[i].get(k)) { can[i].or(can[k]); } } }BitSet的or操作是位运算时间复杂度为O(N²/64)大幅提升了效率。4. 优化技巧与注意事项4.1 输入输出优化使用快速IO类处理大量输入输出static class FastReader { BufferedReader br; StringTokenizer st; public FastReader(InputStream in) { br new BufferedReader(new InputStreamReader(in)); } String next() { while (st null || !st.hasMoreElements()) { try { String line br.readLine(); if (line null) return null; st new StringTokenizer(line); } catch (IOException e) { return null; } } return st.nextToken(); } int nextInt() { return Integer.parseInt(next()); } String nextLine() { try { return br.readLine(); } catch (IOException e) { return null; } } }4.2 边界条件处理需要特别注意几种特殊情况站点到自身的距离为0不可达的站点距离为INF线路末端站点的正确标记相同票价档位的距离比较4.3 内存管理技巧使用基本类型而非包装类合理设置INF值0x3f3f3f3f3f3f3f3fL及时清理临时数据结构使用StringBuilder构建输出结果5. 常见问题与调试经验5.1 重边处理题目说明中提到两个站之间可能有多条直接连接的线路且距离不一定相等。因此在读取输入时需要取最小值if (d dist[prev][v]) dist[prev][v] dist[v][prev] d;5.2 线路末端标记末端站点包括每条线路的起点和终点int u Integer.parseInt(st.nextToken()); isTerminal[u] true; // 起点是末端 int prev u; while (st.hasMoreTokens()) { // ...处理中间站点... prev v; } isTerminal[prev] true; // 终点是末端5.3 性能调优在实际测试中发现使用BitSet比boolean[][]节省约16倍内存预先计算fareMax比每次查询快使用快速IO类可减少约30%的运行时间6. 完整代码解析以下是完整代码的关键部分解析public class Main { static final long INF 0x3f3f3f3f3f3f3f3fL; static int N, M, K; static long[][] dist; static BitSet[] can; static boolean[] isTerminal; public static void main(String[] args) throws Exception { FastReader fr new FastReader(System.in); PrintWriter out new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out))); // 初始化部分 N fr.nextInt(); M fr.nextInt(); K fr.nextInt(); // 数据结构初始化 dist new long[N 1][N 1]; isTerminal new boolean[N 1]; can new BitSet[N 1]; // 距离矩阵初始化 for (int i 1; i N; i) { Arrays.fill(dist[i], INF); dist[i][i] 0; can[i] new BitSet(N 1); } // 输入处理部分 // ...略... // Floyd-Warshall算法 // ...略... // 构建转移图 // ...略... // 传递闭包计算 // ...略... // 查询处理 int Q fr.nextInt(); while (Q-- 0) { int start fr.nextInt(); StringBuilder res new StringBuilder(); boolean first true; for (int j 1; j N; j) { if (j start || can[start].get(j)) { if (!first) res.append( ); res.append(j); first false; } } out.println(res.toString()); } out.flush(); out.close(); } // FastReader类定义 // ...略... }7. 算法复杂度分析时间复杂度Floyd-WarshallO(N³) 200³ 8,000,000转移图构建O(N²) 40,000传递闭包O(N³/64) ≈ 125,000总时间约8,165,000次操作在550ms内可完成空间复杂度dist数组200×200×8B ≈ 320KBBitSet数组200×200/8B ≈ 5KB其他可忽略总内存远小于64MB限制8. 测试用例验证使用题目提供的样例进行验证输入6 2 6 1 6 2 4 3 1 4 5 6 2 6 6 4 2 3 4 5输出1 2 4 5 6 1 2 3 4 5 6 1 2 4 5 6 1 2 4 5 6验证过程从站点2出发车费0元站点2本身车费2元站点1(距离6)站点4(距离4)站点5(距离6)站点6(距离6)站点5和6是末端站点站点1是距离最远从站点3出发可以到达所有站点其他查询同理9. 扩展思考这个问题可以有几种变体如果拍照规则改为最近站点而非最远站点如果换乘需要额外费用如果考虑地铁运行时间限制对于更大规模的数据如N1000可以考虑使用Dijkstra优先队列替代Floyd-Warshall使用更高效的可达性算法并行计算最短路径在实际地铁系统中这类算法可以用于乘客路径规划站点可达性分析票价计算模拟10. 个人实现心得在实现这道题时我最初尝试了普通的boolean数组来存储可达性结果发现内存超出限制。改用BitSet后不仅内存使用大幅下降而且由于位运算的高效性运行时间也有所改善。另一个教训是关于线路末端站点的标记。最初我只标记了线路终点忽略了起点也是末端站点导致部分测试用例失败。这提醒我在处理问题时必须仔细阅读题目描述不遗漏任何细节。对于Java选手来说这类图论题目需要特别注意输入输出效率基本数据类型的使用合理预估数据规模选择合适的数据结构最后这道题很好地结合了图论算法和实际问题场景通过解决它我对Floyd-Warshall算法和BitSet的应用有了更深的理解。在类似的竞赛题目中这种预处理高效查询的思路非常常见值得熟练掌握。
企业数字化 ERP 产品动态
相关推荐
SQL查询技巧:从基础到高级的数据筛选方法 1. SQL查询基础:从零开始掌握数据筛选作为一名常年与数据库打交道的开发者,我深知SQL查询是数据处理的核心技能。无论是简单的用户信息检索,还是复杂的业务数据分析,都离不开这些基础却强大的查询技巧。今天,我将分享几… · 2026/11/3 16:53:43
Git误操作急救手册:从删库到恢复的完整指南 1. Git误操作急救手册:从删库到跑路的救赎之路刚提交完代码准备下班,突然发现手滑把develop分支删了?不小心把数据库密码推到了GitHub?合并分支时发现方向搞反了?作为开发者,这些场景光是想想就让人头皮发麻… · 2026/11/3 16:52:42
专业软件项目计划书编写指南与Word实战技巧 1. 项目概述:为什么需要专业的软件项目计划书?在软件行业摸爬滚打十几年,我见过太多项目因为前期规划不周而陷入泥潭。2026年的软件项目计划书不仅仅是一份文档,更是整个团队的行动纲领和风险控制手册。与传统项目管理不同&#x… · 2026/11/3 16:52:42
网络安全架构与访问控制技术深度解析 1. 网络安全架构的本质认知 网络安全从来不是简单的设备堆砌或策略文档,而是一个动态演进的系统工程。从业十五年,我见过太多企业花费数百万购置高端防火墙却因默认密码被攻破的案例。真正的安全防护需要从三个维度构建:技术体系、管理流程和… · 2026/11/3 17:41:10
WordPress升级PHP 7兼容性实战:从评估到回滚的完整指南 1. 老站升级这件事,为什么值得单独拎出来讲 手里攥着一个跑了三五年的WordPress站点,某天运维群里弹出一条消息:“服务器PHP版本要统一升到7.x了,旧版本下个月停止安全维护。”看到这句话,多数人的第一反应不是兴奋&am… · 2026/11/3 17:41:10
Google开源ARTEMIS:AI Agent驱动Android真机测试框架深度解析 Android 真机测试这块硬骨头,Google 这次直接扔出来一个 AI Agent 框架——ARTEMIS。简单说,它就是让大模型扮演你的测试工程师,自己看屏幕、自己点按钮、自己判断结果,全程不写一行测试脚本。这个项目一开源,社区里马… · 2026/11/3 17:41:10
STK 8.1.1中文手册实战指南:场景建模、Access分析与Globe可视化 简介:本资源是STK(System Tool Kit)8.1.1版本官方英文帮助文档的完整中文翻译手册,面向航天仿真、卫星通信、遥感观测及空间系统建模领域的初学者与工程实践者,旨在解决用户因语言障碍导致的功能理解困难与操作门槛高问… · 2026/11/3 17:41:10
瑞萨MCU开发环境搭建全攻略:从工具选型到工程调试 1. 瑞萨开发环境搭建的整体思路拆解搞嵌入式这行的朋友大概都有个共识:环境搭建这件事,第一次搞的时候能耗掉你大半天,搞通之后回头看又觉得不过如此。瑞萨(Renesas)的MCU在工业控制、汽车电子、家电主控这些领域用得相… · 2026/11/3 17:41:10
视联网产品迭代优化与用户反馈闭环实践 1. 视联网产品迭代优化的核心挑战与机遇 在当前的数字化浪潮中,视联网产品正经历着前所未有的快速发展。作为连接物理世界与数字世界的桥梁,视联网产品面临着独特的迭代优化挑战。与传统的纯软件产品不同,视联网产品涉及硬件设备、网络传输、… · 2026/11/3 17:40:03
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 13:10:28
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 6:04:24
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 5:52:46
STM32F411RE与MAX14431实现SPI隔离:工业现场抗共模干扰实战 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 1:01:59
ESP32+大模型AI硬件开发:从Demo到产品的8个工程问题 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 1:01:59
基于MAX14431BAEE+与PIC18F85J10的SPI隔离方案设计与实践 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 1:01:59
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/2 13:10:28
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 6:04:24
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案 /* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/3 5:52:46