18 KiB
第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。
输入样例:
300
输出样例:
166.00
解题思路: 用多层 if-else if-else 分段累计;计算完成后再独立判断是否加收服务费。
参考代码:
#include <iostream>
#include <iomanip>
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。
输入样例:
10 135 1 1
输出样例:
40
解题思路: 先判断身高;不免费时再按年龄嵌套判断,儿童分支中继续判断陪同;最后对合法票价判断周末加价。
参考代码:
#include <iostream>
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。
输入样例:
5
88 95 90 95 70
输出样例:
95 2
解题思路: 用第一名选手初始化擂主;只有出现严格更高分时才更新,便可保留最早编号。
参考代码:
#include <iostream>
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。
输入样例:
4 80
3 76
8 84
2 84
5 90
输出样例:
2 84
解题思路: 依次比较距离、分数、编号,三层优先级构成完整更新条件。
参考代码:
#include <iostream>
#include <cmath>
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。
输入样例:
86
输出样例:
B
解题思路: 先排除非法范围,再从高到低使用多层 else if。
参考代码:
#include <iostream>
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,月份可能为任意整数。
输入样例:
2024 2
输出样例:
29
解题思路: 先验证月份,再判断 2 月;2 月内部嵌套判断闰年,其余月份判断 30 天或 31 天。
参考代码:
#include <iostream>
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。
输入样例:
17 % 5
输出样例:
2
解题思路: 先按运算符多层分支;进入除法或取模分支后再嵌套判断除数。
参考代码:
#include <iostream>
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。
输入样例:
60 1.70
输出样例:
NORMAL
解题思路: 先计算 weight/(height*height),再按从小到大的边界进行多层判断。
参考代码:
#include <iostream>
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。
输入样例:
3 4 5
输出样例:
SCALENE
RIGHT
解题思路: 先判断合法性;合法后分别进行边型判断和直角判断。直角判断需覆盖三条边分别为斜边的情况。
参考代码:
#include <iostream>
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<w≤100。
输入样例:
6.2 1 1
输出样例:
48.00
解题思路: 先向上取整重量并按档位计算,再依次处理偏远和加急条件。
参考代码:
#include <iostream>
#include <cmath>
#include <iomanip>
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。
输入格式: 两个字符。
输出格式: 裁判结果。
数据范围: 任意可见字符。
输入样例:
R S
输出样例:
A
解题思路: 先检查两个手势是否合法;再判断平局;最后用三个获胜组合判断 A 是否获胜。
参考代码:
#include <iostream>
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 表示。
输入样例:
87 0 60 0
输出样例:
SECOND
解题思路: 违纪是最高优先级;未违纪时按奖项从高到低判断,括号明确“且”“或”的组合。
参考代码:
#include <iostream>
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,价格和评分为正整数。
输入样例:
4
5 100 9
2 120 9
8 80 8
3 100 9
输出样例:
3
解题思路: 第一优先级比较评分,第二优先级比较价格,第三优先级比较编号。
参考代码:
#include <iostream>
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。
数据范围: 成绩可能为任意整数。
输入样例:
78 92 75 0
输出样例:
ADMITTED
解题思路: 先做数据合法性检查,再判断特殊录取,最后按笔试档位嵌套判断面试和体育条件。
参考代码:
#include <iostream>
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;
}
易错提醒: 数据检查、特殊规则、普通规则的优先级不能调换。