
1. 题目背景与需求解析这道UVa 145题目来自著名的ACM国际大学生程序设计竞赛题库属于典型的电信计费系统模拟题。题目设定在一个虚构的Gondwanaland大陆要求我们根据通话记录计算长途电话费用。1.1 题目核心要素题目给出以下关键信息通话时段划分工作日8:00-18:00为高峰时段其他时间为非高峰时段周末全天按非高峰时段计费费率表根据通话距离分为5个等级A-E每个费率等级在不同时段有不同收费标准1.2 计费规则详解计费系统采用按分钟计费模式需要特别注意通话开始和结束时间可能跨越不同计费时段通话可能持续到第二天跨日处理周末的定义周六和周日需要准确判断通话时长不足1分钟按1分钟计算提示实际电信系统中这种时段划分和费率等级的设计非常普遍是典型的电信业务逻辑。2. 解题思路与技术实现2.1 时间处理方案处理时间相关的逻辑是本题的核心难点。我采用以下数据结构struct Time { int day; // 1周一, ..., 7周日 int hour; int minute; };关键算法步骤将输入字符串解析为Time结构实现时间递增函数处理跨日计算两个时间的分钟差判断当前时间属于哪个计费时段2.2 费率计算策略采用分层计算法将通话过程按计费时段拆分为多个时间段对每个时间段计算持续分钟数根据费率等级和时段类型累加费用double calculateCharge(Time start, Time end, char rate) { double total 0.0; Time current start; while (current end) { Time next getNextRateChange(current); if (next end) next end; int minutes getMinutes(current, next); double rate getRate(current, rate); total minutes * rate; current next; } return total; }2.3 输入输出处理输入格式示例A 123-4567 123-4567 01/01/2003 08:30 01/01/2003 09:45需要特别注意电话号码中的破折号处理日期格式的解析DD/MM/YYYY多个测试用例的连续处理3. 实现细节与优化技巧3.1 时间处理优化为避免重复计算可以预先生成一周内所有时间点的时段标记// 预生成时段表0非高峰1高峰 int ratePeriod[8][24]; // [day][hour] void initRatePeriod() { for (int day 1; day 5; day) { for (int hour 8; hour 18; hour) { ratePeriod[day][hour] 1; // 工作日高峰 } } }3.2 边界条件处理特别注意以下边界情况通话开始和结束在同一分钟通话跨越午夜日期变更通话持续超过24小时闰年和不同月份的天数处理3.3 测试用例设计建议测试以下典型场景完全在高峰时段的通话完全在非高峰时段的通话跨时段通话如17:50-18:30周末通话跨日通话如23:30-00:30不足1分钟的通话4. 常见问题与调试技巧4.1 典型错误分析时段判断错误最常见的错误是高峰时段判断不准确特别是18:00是否包含在内跨日处理遗漏忘记处理23:59到00:00的过渡费率等级混淆将不同等级的费用计算错误分钟舍入错误59秒应该向上舍入为1分钟4.2 调试建议打印中间计算结果特别是时段划分和费率应用对时间处理函数进行单元测试使用已知结果的测试用例验证检查浮点数计算的精度问题注意电信计费系统对精度要求极高建议使用定点数或整数计算以分为单位避免浮点误差。4.3 性能优化虽然本题对性能要求不高但良好的实践包括避免在循环中进行重复计算使用查表法替代实时判断减少不必要的对象构造使用更高效的时间表示方法如自纪元开始的分钟数5. 扩展思考与实际应用5.1 现实电信系统的差异实际电信计费系统更加复杂可能包含首次分钟特殊计费套餐余量抵扣节假日特殊费率国际长途附加费增值税和其他税费5.2 类似问题拓展这类时间分段计费问题还出现在电力系统峰谷计价停车场收费系统酒店房费计算员工加班费计算5.3 代码重构建议为进一步提高代码质量可以考虑将费率表配置化从文件读取实现策略模式处理不同计费规则使用工厂方法创建不同的计费器添加日志记录功能我在实际实现中发现将时间处理逻辑与计费逻辑分离可以大大提高代码的可维护性。例如单独实现一个TimePeriod类来处理时间段的划分再与计费策略组合使用。这样当计费规则变化时只需修改计费策略部分时间处理逻辑可以保持不变。