# 第4课编程题(教师版) ## 本课知识点覆盖表 | 核心知识点 | GESP等级 | 对应课堂题 | |---|---|---| | `if / else if / else` 多层互斥分支 | 一级必考 | 课堂1 | | 嵌套 `if`、逻辑运算与条件分组 | 一级必考 | 课堂2 | | 普通打擂台、合法初始擂主 | 一级/二级 | 课堂3 | | 二次打擂台、主条件与并列规则 | 二级 | 课堂4 | > 本课重点训练多层分支结构。14 题中有 10 题需要三层以上分支或嵌套判断。 ## 一、课堂练习(4题) ### 课堂1:阶梯电费【适中】 **题目描述:** 某月用电量不超过 180 度的部分每度 0.50 元;181~280 度的部分每度 0.60 元;超过 280 度的部分每度 0.80 元。若总电费超过 200 元再加收 5% 服务费。输出应付金额。 **输入格式:** 输入一个非负整数,表示本月用电量。 **输出格式:** 应付金额,保留两位小数。 **数据范围:** `0≤n≤10000`。 **输入样例:** ```text 300 ``` **输出样例:** ```text 166.00 ``` **解题思路:** 用多层 `if-else if-else` 分段累计;计算完成后再独立判断是否加收服务费。 **参考代码:** ```cpp #include #include using namespace std; int main() { int n; cin >> n; double cost; if (n <= 180) { cost = n * 0.50; } else if (n <= 280) { cost = 180 * 0.50 + (n - 180) * 0.60; } else { cost = 180 * 0.50 + 100 * 0.60 + (n - 280) * 0.80; } if (cost > 200) cost *= 1.05; cout << fixed << setprecision(2) << cost; return 0; } ``` **易错提醒:** 阶梯收费是分段累计,不是把全部用电量直接乘最高档单价。 ### 课堂2:游乐园购票方案【适中】 **题目描述:** 输入年龄、身高和是否有成人陪同。身高低于 120 厘米免费;否则年龄不满 12 岁时,有成人陪同票价 30 元,无陪同不得入园;12~59 岁票价 80 元;60 岁及以上票价 40 元。周末所有非免费票加收 10 元。 **输入格式:** 依次输入年龄、身高、是否有成人陪同和是否为周末;后两项用 0 或 1 表示。 **输出格式:** 免费输出 `FREE`,不得入园输出 `DENIED`,否则输出票价。 **数据范围:** `1≤age≤120`,`50≤height≤220`。 **输入样例:** ```text 10 135 1 1 ``` **输出样例:** ```text 40 ``` **解题思路:** 先判断身高;不免费时再按年龄嵌套判断,儿童分支中继续判断陪同;最后对合法票价判断周末加价。 **参考代码:** ```cpp #include using namespace std; int main() { int age, height, accompanied, weekend; cin >> age >> height >> accompanied >> weekend; if (height < 120) { cout << "FREE"; } else { int price; if (age < 12) { if (accompanied == 0) { cout << "DENIED"; return 0; } price = 30; } else if (age < 60) { price = 80; } else { price = 40; } if (weekend == 1) price += 10; cout << price; } return 0; } ``` **易错提醒:** “不得入园”不是票价 0;输出后应立即结束,避免继续加价。 ### 课堂3:最佳选手【适中】 **题目描述:** 输入 `n` 名选手的分数,输出最高分和第一次取得该分数的选手编号。 **输入格式:** 第一行输入选手人数;第二行输入每名选手的分数。 **输出格式:** 最高分和选手编号(从 1 开始)。 **数据范围:** `1≤n≤100`,分数为 `0~100`。 **输入样例:** ```text 5 88 95 90 95 70 ``` **输出样例:** ```text 95 2 ``` **解题思路:** 用第一名选手初始化擂主;只有出现严格更高分时才更新,便可保留最早编号。 **参考代码:** ```cpp #include using namespace std; int main() { int n, score, bestScore, bestId = 1; cin >> n >> bestScore; for (int id = 2; id <= n; id++) { cin >> score; if (score > bestScore) { bestScore = score; bestId = id; } } cout << bestScore << " " << bestId; return 0; } ``` **易错提醒:** 擂主必须用第一个合法数据初始化;相等时不更新才能保留第一次出现的位置。 ### 课堂4:最接近目标的候选人【适中】 **题目描述:** 输入目标分 `target` 以及 `n` 名候选人的编号和分数。选择与目标分距离最小者;距离相同时选分数较高者;仍相同则选编号较小者。 **输入格式:** 第一行输入候选人数和目标分;随后每行输入一名候选人的编号和分数。 **输出格式:** 入选者编号和分数。 **数据范围:** `1≤n≤100`,编号互不相同,分数为 `0~100`。 **输入样例:** ```text 4 80 3 76 8 84 2 84 5 90 ``` **输出样例:** ```text 2 84 ``` **解题思路:** 依次比较距离、分数、编号,三层优先级构成完整更新条件。 **参考代码:** ```cpp #include #include using namespace std; int main() { int n, target, id, score, bestId, bestScore; cin >> n >> target; cin >> bestId >> bestScore; for (int i = 1; i < n; i++) { cin >> id >> score; int d = abs(score - target); int bestD = abs(bestScore - target); if (d < bestD || (d == bestD && score > bestScore) || (d == bestD && score == bestScore && id < bestId)) { bestId = id; bestScore = score; } } cout << bestId << " " << bestScore; return 0; } ``` **易错提醒:** 三层规则按先后顺序连接,每个次级规则都只能在前级相等时生效。 ## 二、课后作业(3题) ### 课后1:成绩等级【简单】 **题目描述:** 输入成绩:90~100 为 `A`,80~89 为 `B`,70~79 为 `C`,60~69 为 `D`,0~59 为 `E`;范围外输出 `ERROR`。 **输入格式:** 一个整数成绩。 **输出格式:** 等级或 `ERROR`。 **数据范围:** 输入整数绝对值不超过 1000。 **输入样例:** ```text 86 ``` **输出样例:** ```text B ``` **解题思路:** 先排除非法范围,再从高到低使用多层 `else if`。 **参考代码:** ```cpp #include using namespace std; int main() { int score; cin >> score; if (score < 0 || score > 100) cout << "ERROR"; else if (score >= 90) cout << "A"; else if (score >= 80) cout << "B"; else if (score >= 70) cout << "C"; else if (score >= 60) cout << "D"; else cout << "E"; return 0; } ``` **易错提醒:** 从高到低判断后,不需要重复写上界。 ### 课后2:月份天数【简单】 **题目描述:** 输入年份和月份,输出该月天数。闰年规则:能被 400 整除,或能被 4 整除但不能被 100 整除。 **输入格式:** 输入年份和月份。 **输出格式:** 天数;月份非法输出 `ERROR`。 **数据范围:** `1≤year≤9999`,月份可能为任意整数。 **输入样例:** ```text 2024 2 ``` **输出样例:** ```text 29 ``` **解题思路:** 先验证月份,再判断 2 月;2 月内部嵌套判断闰年,其余月份判断 30 天或 31 天。 **参考代码:** ```cpp #include using namespace std; int main() { int year, month; cin >> year >> month; if (month < 1 || month > 12) { cout << "ERROR"; } else if (month == 2) { bool leap = year % 400 == 0 || (year % 4 == 0 && year % 100 != 0); cout << (leap ? 29 : 28); } else if (month == 4 || month == 6 || month == 9 || month == 11) { cout << 30; } else { cout << 31; } return 0; } ``` **易错提醒:** 闰年条件中的括号不能省略概念上的分组。 ### 课后3:简单计算器【简单】 **题目描述:** 输入两个整数和运算符 `+ - * / %`,输出计算结果。除数为 0 时输出 `ERROR`,未知运算符输出 `UNKNOWN`。 **输入格式:** 依次输入第一个整数、运算符和第二个整数。 **输出格式:** 计算结果或错误信息。 **数据范围:** 两数绝对值不超过 10000。 **输入样例:** ```text 17 % 5 ``` **输出样例:** ```text 2 ``` **解题思路:** 先按运算符多层分支;进入除法或取模分支后再嵌套判断除数。 **参考代码:** ```cpp #include using namespace std; int main() { int a, b; char op; cin >> a >> op >> b; if (op == '+') cout << a + b; else if (op == '-') cout << a - b; else if (op == '*') cout << a * b; else if (op == '/' || op == '%') { if (b == 0) cout << "ERROR"; else if (op == '/') cout << a / b; else cout << a % b; } else { cout << "UNKNOWN"; } return 0; } ``` **易错提醒:** 除法和取模都必须先检查除数是否为 0。 ## 三、扩展练习(7题) ### 扩展1:体质指数评价【基础综合】 **题目描述:** 输入体重(千克)和身高(米),计算 BMI。低于 18.5 输出 `LOW`,18.5~23.9 输出 `NORMAL`,24~27.9 输出 `HIGH`,28 及以上输出 `VERY HIGH`。 **输入格式:** 输入体重和身高两个实数。 **输出格式:** BMI 等级。 **数据范围:** `20≤weight≤300`,`1≤height≤2.5`。 **输入样例:** ```text 60 1.70 ``` **输出样例:** ```text NORMAL ``` **解题思路:** 先计算 `weight/(height*height)`,再按从小到大的边界进行多层判断。 **参考代码:** ```cpp #include using namespace std; int main() { double weight, height; cin >> weight >> height; double bmi = weight / (height * height); if (bmi < 18.5) cout << "LOW"; else if (bmi < 24) cout << "NORMAL"; else if (bmi < 28) cout << "HIGH"; else cout << "VERY HIGH"; return 0; } ``` **易错提醒:** 身高要平方;连续区间判断必须保证没有空档或重叠。 ### 扩展2:三角形分类【中等】 **题目描述:** 输入三条边。不能组成三角形输出 `INVALID`;否则先按边分类输出 `EQUILATERAL`、`ISOSCELES` 或 `SCALENE`,再输出是否为直角三角形 `RIGHT` 或 `NOT RIGHT`。 **输入格式:** 输入三个正整数,表示三条边长。 **输出格式:** 两行分类结果。 **数据范围:** 边长不超过 10000。 **输入样例:** ```text 3 4 5 ``` **输出样例:** ```text SCALENE RIGHT ``` **解题思路:** 先判断合法性;合法后分别进行边型判断和直角判断。直角判断需覆盖三条边分别为斜边的情况。 **参考代码:** ```cpp #include using namespace std; int main() { long long a, b, c; cin >> a >> b >> c; if (a + b <= c || a + c <= b || b + c <= a) { cout << "INVALID"; return 0; } if (a == b && b == c) cout << "EQUILATERAL\n"; else if (a == b || a == c || b == c) cout << "ISOSCELES\n"; else cout << "SCALENE\n"; if (a * a + b * b == c * c || a * a + c * c == b * b || b * b + c * c == a * a) cout << "RIGHT"; else cout << "NOT RIGHT"; return 0; } ``` **易错提醒:** 必须先判断能否组成三角形;平方可能较大,应使用 `long long`。 ### 扩展3:快递计费【中等】 **题目描述:** 基础运费按重量计算:不超过 1 千克 8 元;1~5 千克每增加 1 千克加 3 元,不足 1 千克按 1 千克算;超过 5 千克的部分每千克加 5 元。偏远地区加 10 元,加急再加总价的 20%。 **输入格式:** 依次输入包裹重量、是否为偏远地区和是否加急;后两项用 0 或 1 表示。 **输出格式:** 运费,保留两位小数。 **数据范围:** `0 #include #include using namespace std; int main() { double w; int remote, urgent; cin >> w >> remote >> urgent; int kg = (int)ceil(w); double cost; if (kg <= 1) cost = 8; else if (kg <= 5) cost = 8 + (kg - 1) * 3; else cost = 8 + 4 * 3 + (kg - 5) * 5; if (remote) cost += 10; if (urgent) cost *= 1.2; cout << fixed << setprecision(2) << cost; return 0; } ``` **易错提醒:** 示例中 6.2 千克按 7 千克计算;加急费在偏远附加费之后计算。 ### 扩展4:石头剪刀布裁判【中等】 **题目描述:** 输入两名选手的手势 `R`(石头)、`S`(剪刀)、`P`(布)。非法手势输出 `ERROR`;相同输出 `DRAW`;否则输出 `A` 或 `B`。 **输入格式:** 两个字符。 **输出格式:** 裁判结果。 **数据范围:** 任意可见字符。 **输入样例:** ```text R S ``` **输出样例:** ```text A ``` **解题思路:** 先检查两个手势是否合法;再判断平局;最后用三个获胜组合判断 A 是否获胜。 **参考代码:** ```cpp #include using namespace std; int main() { char a, b; cin >> a >> b; bool validA = a == 'R' || a == 'S' || a == 'P'; bool validB = b == 'R' || b == 'S' || b == 'P'; if (!validA || !validB) cout << "ERROR"; else if (a == b) cout << "DRAW"; else if ((a == 'R' && b == 'S') || (a == 'S' && b == 'P') || (a == 'P' && b == 'R')) cout << "A"; else cout << "B"; return 0; } ``` **易错提醒:** 合法性判断必须放在胜负判断之前。 ### 扩展5:奖学金评定【中等】 **题目描述:** 输入平均分、竞赛获奖次数、志愿服务时长和是否违纪。违纪直接输出 `NONE`;否则平均分≥90 且获奖≥2 为一等奖,平均分≥85 且(获奖≥1 或服务≥50)为二等奖,平均分≥80 或服务≥100 为三等奖,其余无奖。 **输入格式:** 依次输入平均分、获奖次数、志愿服务时长和是否违纪。 **输出格式:** `FIRST`、`SECOND`、`THIRD` 或 `NONE`。 **数据范围:** 平均分 `0~100`,其余为非负整数,违纪用 0/1 表示。 **输入样例:** ```text 87 0 60 0 ``` **输出样例:** ```text SECOND ``` **解题思路:** 违纪是最高优先级;未违纪时按奖项从高到低判断,括号明确“且”“或”的组合。 **参考代码:** ```cpp #include using namespace std; int main() { int average, awards, service, violation; cin >> average >> awards >> service >> violation; if (violation) cout << "NONE"; else if (average >= 90 && awards >= 2) cout << "FIRST"; else if (average >= 85 && (awards >= 1 || service >= 50)) cout << "SECOND"; else if (average >= 80 || service >= 100) cout << "THIRD"; else cout << "NONE"; return 0; } ``` **易错提醒:** 一定要从高等级奖项向低等级判断,否则较宽条件会抢先匹配。 ### 扩展6:最佳商品【略难】 **题目描述:** 输入 `n` 件商品的编号、价格和评分。选择评分最高的商品;评分相同时价格更低者优先;仍相同则编号更小者优先。 **输入格式:** 第一行输入商品数量;随后每行输入一件商品的编号、价格和评分。 **输出格式:** 最佳商品编号。 **数据范围:** `1≤n≤100`,价格和评分为正整数。 **输入样例:** ```text 4 5 100 9 2 120 9 8 80 8 3 100 9 ``` **输出样例:** ```text 3 ``` **解题思路:** 第一优先级比较评分,第二优先级比较价格,第三优先级比较编号。 **参考代码:** ```cpp #include using namespace std; int main() { int n, id, price, score; int bestId, bestPrice, bestScore; cin >> n >> bestId >> bestPrice >> bestScore; for (int i = 1; i < n; i++) { cin >> id >> price >> score; if (score > bestScore || (score == bestScore && price < bestPrice) || (score == bestScore && price == bestPrice && id < bestId)) { bestId = id; bestPrice = price; bestScore = score; } } cout << bestId; return 0; } ``` **易错提醒:** 不要用任意极值初始化三个擂台变量,直接读入第一件商品最安全。 ### 扩展7:综合录取规则【略难】 **题目描述:** 输入笔试、面试、体育三项成绩,以及是否有竞赛一等奖。任一成绩不在 0~100 输出 `ERROR`。竞赛一等奖且笔试≥70 可直接录取;否则笔试≥85 时,面试≥80 且体育≥60 录取;笔试 75~84 时,面试≥90 且体育≥70 才录取;其他情况不录取。 **输入格式:** 依次输入笔试成绩、面试成绩、体育成绩和是否获得竞赛一等奖;最后一项用 0 或 1 表示。 **输出格式:** `ADMITTED`、`REJECTED` 或 `ERROR`。 **数据范围:** 成绩可能为任意整数。 **输入样例:** ```text 78 92 75 0 ``` **输出样例:** ```text ADMITTED ``` **解题思路:** 先做数据合法性检查,再判断特殊录取,最后按笔试档位嵌套判断面试和体育条件。 **参考代码:** ```cpp #include using namespace std; int main() { int written, interview, sport, prize; cin >> written >> interview >> sport >> prize; if (written < 0 || written > 100 || interview < 0 || interview > 100 || sport < 0 || sport > 100) { cout << "ERROR"; } else if (prize == 1 && written >= 70) { cout << "ADMITTED"; } else if (written >= 85) { if (interview >= 80 && sport >= 60) cout << "ADMITTED"; else cout << "REJECTED"; } else if (written >= 75) { if (interview >= 90 && sport >= 70) cout << "ADMITTED"; else cout << "REJECTED"; } else { cout << "REJECTED"; } return 0; } ``` **易错提醒:** 数据检查、特殊规则、普通规则的优先级不能调换。