资讯动态

PTA习题2-2阶梯电价:C语言条件分支与边界值实战解析

发布时间:2026/10/23 3:21:16 来源:尧图企业网站定制
PTA 上这道“习题2-2 阶梯电价”我印象挺深。刚看到题目时我第一反应是“这不就是小学应用题嘛”分段乘单价再求和能有多难结果真正在评测系统里提交的时候连续踩了好几个坑才意识到这道入门题考察的不只是数学更是条件分支逻辑、边界值处理和格式化输出这些编程基本功。这篇文章就把我从读题到提交通过的完整过程拆开讲一遍顺便聊聊这道题背后值得琢磨的工程化思维。1. 题目解析阶梯电价背后的三个计算档位和判定逻辑1.1 业务规则转换成程序条件先看懂什么情况下用哪个价格阶梯电价是居民生活用电里常见的计费方式规则本身不复杂第一档月用电量不超过 200 度按基础电价计算每度 0.55 元第二档月用电量在 201 度到 400 度之间超过 200 度的那部分按每度 0.60 元计算第三档月用电量超过 400 度超过 400 度的那部分按每度 0.85 元计算。注意这个“那部分”三个字是整个题目的核心。很多人一开始会写成“用电量在 201 到 400 之间电费 用电量 × 0.60”这就完全错了。阶梯计费不是“整段统一涨价”而是“分档累进”。拿 350 度举例正确算法是前 200 度200 × 0.55 110 元超出的 150 度150 × 0.60 90 元合计110 90 200 元。如果错误地按 350 × 0.60 210 元计算就多算了 10 元。放在实际生活中这就是一笔糊涂账放在编程题里这就是“答案错误”的典型原因。把业务规则翻译成程序逻辑时我习惯先画一张“档位归属表”用电量区间0 到 200 度201 到 400 度400 度以上基础部分价格0.55 元/度0.55 元/度前 200 度0.55 元/度前 200 度超额部分价格无0.60 元/度超出部分0.60 元/度201-400 度部分更高部分价格无无0.85 元/度超出 400 度部分这张表看起来啰嗦但写代码前把逻辑想清楚比任何技巧都重要。程序里的 if-else 结构本质就是把这张表一行一行地翻译成“如果……那么……”的判断语句。1.2 输入输出规范与“保留两位小数”的注意点PTA 题目的输入输出格式很严格阶梯电价这题通常要求输入一个整数表示月用电量输出一个实数表示应付电费并且保留两位小数。前 100 字里的关键词“PTA”“习题 2-2”“阶梯电价”都在提示这是一个面向在线评测的编程任务。输出格式里那个“保留两位小数”经常被初学者当成小事一桩其实它牵扯到三个层面的问题C 语言里 printf 的格式化控制%.2lf能精确控制小数位数浮点数本身的存储误差0.55、0.60、0.85 这些小数在计算机里是近似存储的累加后可能产生细微偏差评测系统比较答案时通常采用“相对误差”或“绝对误差”的判定方式但如果你输出了 110.5 而不是 110.50格式不对也会被判错。有些同学在本地编译器里运行结果“肉眼看着没问题”但提交就是过不了往往就是栽在输出格式上。后面我会专门讲这块。2. 编码思路if-else 分支结构的三段式写法与判断顺序2.1 最直接的实现三段式 if-else 链条阶梯电价这类分段函数最朴素也最好读的写法就是 if-else if-else 链条。逻辑上完全照抄业务规则if (electricity 200) { cost electricity * 0.55; } else if (electricity 400) { cost 200 * 0.55 (electricity - 200) * 0.60; } else { cost 200 * 0.55 200 * 0.60 (electricity - 400) * 0.85; }这个链条之所以推荐是因为它天然利用了“顺序判定”的短路特性。程序从上往下走第一个条件不满足才轮到第二个条件判断所以第二个else if里不需要再写electricity 200 electricity 400这种双重条件。如果写了虽然也能跑但代码会显得冗余。这里我特别想强调一件事判断顺序不能乱。假如你把electricity 400写在最前面那么用电量 150 度也会命中这个分支就会错误地套用第二档价格。不要觉得这是低级错误——我见过很多初学两周的同学在调试时折腾半小时最后发现问题就是 if 的顺序写反了。2.2 边界值 200 和 400小于、等于、大于到底归哪一档边界值是这种分段题最容易出错的地方。题目里一般会说“不超过 200 度按第一档”“201 到 400 度之间按第二档”。那么问题来了200 度整和 400 度整到底算哪一档通常的规则设定是“不超过 200 度”包含 200 本身所以判断条件应该是 200而不是 200。同理“201 到 400”包含 400条件应该写成 400。这样设计之后等于号的归属就清晰了200 度整 → 走第一档400 度整 → 走第二档此时费用 200 × 0.55 200 × 0.60 230 元401 度 → 走第三档费用 200 × 0.55 200 × 0.60 1 × 0.85 230.85 元。这些边界值单独拎出来手工算一遍再拿程序跑一遍确认完全一致才叫“边界测试到位”。实际刷题时很多人用 150、300、500 这种“安全值”测试全是绿的一提交就红就是因为没测临界点。2.3 换一种思路先减档位再算费用能不能省代码有些同学喜欢把代码写得很短比如下面的思路cost electricity * 0.55; if (electricity 200) cost (electricity - 200) * 0.05; if (electricity 400) cost (electricity - 400) * 0.25;这个思路的本质是先全部按第一档价格算然后给“超过 200 度的那部分”补每度 0.05 元的差价再给“超过 400 度的那部分”补每度 0.25 元的差价。这样做确实代码更短而且避免了多重 if 嵌套。但我不建议初学者在 PTA 上这么写原因有两个可读性差。0.05 和 0.25 这两个“差价系数”是算出来的不是业务规则里直接给出的别人看代码时还得先在脑子里做一遍减法一旦题目改成多档复杂计价这种“补差价”写法会变得极其难维护。当然如果是工作多年后写内部工具这种技巧能减少重复代码也不是不能用。但刷题阶段我更推荐“把每个档位的价格因子老老实实写出来”。3. 完整提交代码与逐行解释从 scanf 到 printf 的每一步3.1 参考代码C 语言版我最终提交的代码如下实测可以在评测系统里通过#include stdio.h int main() { int electricity; double cost; scanf(%d, electricity); if (electricity 200) { cost electricity * 0.55; } else if (electricity 400) { cost 200 * 0.55 (electricity - 200) * 0.60; } else { cost 200 * 0.55 200 * 0.60 (electricity - 400) * 0.85; } printf(%.2lf\n, cost); return 0; }这段代码非常简短但每一行都有讲究。下面逐行拆给你看。3.2 逐行拆解变量类型、运算符优先级和格式化输出先看声明部分int electricity; double cost;用电量是整数因为题目输入限定了整数电费是小数所以用 double。这个选择看似理所当然但真有人把 electricity 也定义成 double虽然不影响结果却没有必要。还有人在计算时把200 * 0.55写成了200 * 55 / 100结果因为整数除法直接丢了小数部分这种坑后面细说。再看判断部分也就是核心算法。200 * 0.55 (electricity - 200) * 0.60这一行从右往左看(electricity - 200)是超出 200 度的部分* 0.60是这部分按第二档单价计费前面的200 * 0.55是第一档的费用。这种写法把“固定部分”和“变动部分”分得很清楚即使以后价格调整你也能很快定位到要改哪一行。最后看输出部分printf(%.2lf\n, cost);%.2lf的意思是输出 double 类型并且保留两位小数。后面的\n是换行PTA 的评测系统对换行极其敏感。有人觉得“我多一个换行少一个换行无所谓”实际上标准输出和期望输出必须精确匹配多一个空格、少一个换行都可能导致格式错误。3.3 浮点数比较与精度electricity 是整数为什么费用要用 double这里有一个值得深挖的问题为什么费用变量不用 float而是用 doubleC 语言里 double 的双精度浮点数有效位数大约 15 到 16 位十进制数字float 只有大约 7 位。对这道题来说电费最多几百块float 好像也够用。但问题是浮点数的存储是二进制的像 0.55 这种十进制小数无法精确表示累加之后可能产生微小的偏差。举个例子float a 0.55f; float b a a a a a a a a a a;理论上 10 个 0.55 相加应该是 5.5但 float 的实际结果可能是 5.4999995 或者 5.5000005。printf 保留两位小数通常能把这些误差“掩盖”掉因为格式化输出会自动四舍五入到 5.50。但如果中间计算链条更长或者评测系统的判定方式更严格误差就可能被放大。所以能上 double 就上 double这是刷题阶段就该养成的习惯。另外不要拿浮点数直接做相等比较比如if (cost 110.0)这种写法在浮点数场景下是危险的应该用if (fabs(cost - 110.0) 0.0001)这种容差比较。4. PTA 提交时的典型报错与排查思路4.1 答案错误但代码看起来“没问题”重新检查整数除法和公式我第一次提交这道题时返回“答案错误”当时整个人是懵的。本地运行几个样例都正常为什么系统不认后来发现我把其中一个计算写成了(electricity - 200) / 1 * 0.60虽然除以 1 不影响数值但反映了我的公式书写习惯很乱。更经典的错误是“整数除法”cost 200 * 55 / 100 (electricity - 200) * 60 / 100;如果你把 0.55 写成55 / 100C 语言会先执行整数除法55 / 100 0整个第一档费用直接变成 0。正确写法是200 * 55 / 100.0用浮点数参与运算。或者干脆直接写 0.55一个字都别省。排查这类问题时我的建议是把题目给的样例输入挨个跑一遍然后用“断点思维”人工模拟一次。比如输入 350程序先走第一个 if 条件350 200为假走第二个条件350 400为真进入分支计算200 * 0.55 (350 - 200) * 0.60得到 110 90 200。只要有一处中间结果和你手工算的不一致问题就暴露了。4.2 编译错误漏头文件、变量未初始化、中文标点混入PTA 的编译错误提示通常会给出行号但初学者经常看不懂。比较常见的几种忘记写#include stdio.hscanf 和 printf 都没有声明变量声明了但没初始化直接参与计算会拿到“垃圾值”评测环境里可能每次运行结果都不一样中文输入法没切回来把分号写成了全角符号编译器直接报错。我自己踩得最多的是最后一种。写代码时中文注释和代码混杂输入法一不小心就切晚了一个全角分号就能让整个编译失败。解决办法也很简单写完代码编译前肉眼扫一遍分号、括号、引号确认都是半角字符。用编译器的时候把“显示空白字符”打开一般能第一时间发现问题。4.3 格式化错误空格、换行与 %.2lf 的细微差别还有一个常见裁判结果是“格式错误”提示信息和“答案错误”不一样但同样让人沮丧。格式错误的根源通常是输出多了一个空格比如写成printf(%.2lf , cost);末尾多了个空格忘了换行评测比对时输出文件和期望文件最后一行对不上写了%.2f而不是%.2lf虽然在很多 64 位环境下两者效果一样但严谨起见double 就用%lffloat 才用%f。有一个小技巧把输出语句单独放一行前后不要跟多余的字符。比如printf(%.2lf\n, cost);一眼看去就知道输出内容只有“一个保留两位小数的数字 一个换行”不会有额外干扰。5. 从习题到真实项目的延伸阶梯计价模型如何做得更通用5.1 把档位和单价抽成数组一份代码适配多种阶梯规则刷完这道题如果只是“提交通过万事大吉”那收获有限。我建议你再往前走一步思考一个问题如果下个月电价规则变了代码要怎么改用前面的 if-else 硬编码写法每次调价都得去改魔法数字 0.55、0.60、0.85还要小心别改错分支。真实项目里更通用的做法是把档位上界和对应单价存进数组用循环来计算int tier_limits[] {200, 400, INT_MAX}; double tier_prices[] {0.55, 0.60, 0.85}; int tier_count 3; int remaining electricity; double total 0.0; for (int i 0; i tier_count; i) { int current_limit tier_limits[i] - (i 0 ? 0 : tier_limits[i - 1]); if (remaining current_limit) { total current_limit * tier_prices[i]; remaining - current_limit; } else { total remaining * tier_prices[i]; remaining 0; break; } } printf(%.2lf\n, total);这段代码的价值在于你想调整档位门槛和价格时只需改数组里的数字逻辑部分可以原封不动。放到真实业务里这对应着“配置化”的思想——把经常变化的参数从代码里抽出来改成配置文件或数据库字典下次调价不用重新发布版本。5.2 扩展思考分时电价、季节电价与按年累计阶梯阶梯电价只是计价模型中最简单的一种。现实中还有更复杂的规则分时电价白天一个价、晚上一个价需要按小时拆分用电量季节电价夏季和冬季的阶梯门槛不同需要引入时间维度按年累计阶梯每月用电量累加超过年度总门槛后叠加更高单价需要跨账单周期维护状态。如果你把“阶梯电价”这道题的模型吃透了后面这些复杂场景无非是“规则多维度化”的延伸。这就像盖房子——地基打牢了楼层高低只是工程量问题。5.3 刷题之外这道题教会我的三个编程习惯第一动手写代码前先手算边界值。这个习惯看着简单但能帮你避免大量无效调试。不管是 0 度、200 度、400 度还是 1000 度先把期望答案算出来再拿程序跑一次能过就说明逻辑基本没跑偏。第二保持代码的可读性不用刻意追求“最少行数”。阶梯电价这道题10 行和 30 行的解法都能通过但半年后回来看你能快速读懂的那个版本才是好版本。第三测试时带上“异常输入”的思考。虽然题目说输入是整数但你想过输入为负数会发生什么吗合理程序至少不应该把负用电量算成正电费。这种“防御性思维”在项目开发里同样重要。最后再分享一个个人心得我在实际练习中习惯把每道题当“小项目”对待而不是“要交的作业”。做完基础版本后再问自己三个问题——如果输入范围扩大怎么办如果规则变化怎么办如果别人接手这段代码能看懂吗阶梯电价这道题本身很简单但它对应的“分段计费”思想在话费套餐、物流运费、停车场收费这些场景里到处都是。把一道入门题吃透比囫囵吞枣刷十道题更有用。下次再遇到“分段累进”的题目你会觉得特别亲切。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑