Files
project1/第01课-数据类型与分支结构/分支结构-编程题-教师版.md

682 lines
18 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 第4课编程题教师版
## 本课知识点覆盖表
| 核心知识点 | GESP等级 | 对应课堂题 |
|---|---|---|
| `if / else if / else` 多层互斥分支 | 一级必考 | 课堂1 |
| 嵌套 `if`、逻辑运算与条件分组 | 一级必考 | 课堂2 |
| 普通打擂台、合法初始擂主 | 一级/二级 | 课堂3 |
| 二次打擂台、主条件与并列规则 | 二级 | 课堂4 |
> 本课重点训练多层分支结构。14 题中有 10 题需要三层以上分支或嵌套判断。
## 一、课堂练习4题
### 课堂1阶梯电费【适中】
**题目描述:** 某月用电量不超过 180 度的部分每度 0.50 元181280 度的部分每度 0.60 元;超过 280 度的部分每度 0.80 元。若总电费超过 200 元再加收 5% 服务费。输出应付金额。
**输入格式:** 输入一个非负整数,表示本月用电量。
**输出格式:** 应付金额,保留两位小数。
**数据范围:** `0≤n≤10000`
**输入样例:**
```text
300
```
**输出样例:**
```text
166.00
```
**解题思路:** 用多层 `if-else if-else` 分段累计;计算完成后再独立判断是否加收服务费。
**参考代码:**
```cpp
#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 元无陪同不得入园1259 岁票价 80 元60 岁及以上票价 40 元。周末所有非免费票加收 10 元。
**输入格式:** 依次输入年龄、身高、是否有成人陪同和是否为周末;后两项用 0 或 1 表示。
**输出格式:** 免费输出 `FREE`,不得入园输出 `DENIED`,否则输出票价。
**数据范围:** `1≤age≤120``50≤height≤220`
**输入样例:**
```text
10 135 1 1
```
**输出样例:**
```text
40
```
**解题思路:** 先判断身高;不免费时再按年龄嵌套判断,儿童分支中继续判断陪同;最后对合法票价判断周末加价。
**参考代码:**
```cpp
#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`,分数为 `0100`
**输入样例:**
```text
5
88 95 90 95 70
```
**输出样例:**
```text
95 2
```
**解题思路:** 用第一名选手初始化擂主;只有出现严格更高分时才更新,便可保留最早编号。
**参考代码:**
```cpp
#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`,编号互不相同,分数为 `0100`
**输入样例:**
```text
4 80
3 76
8 84
2 84
5 90
```
**输出样例:**
```text
2 84
```
**解题思路:** 依次比较距离、分数、编号,三层优先级构成完整更新条件。
**参考代码:**
```cpp
#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成绩等级【简单】
**题目描述:** 输入成绩90100 为 `A`8089 为 `B`7079 为 `C`6069 为 `D`059 为 `E`;范围外输出 `ERROR`
**输入格式:** 一个整数成绩。
**输出格式:** 等级或 `ERROR`
**数据范围:** 输入整数绝对值不超过 1000。
**输入样例:**
```text
86
```
**输出样例:**
```text
B
```
**解题思路:** 先排除非法范围,再从高到低使用多层 `else if`
**参考代码:**
```cpp
#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`,月份可能为任意整数。
**输入样例:**
```text
2024 2
```
**输出样例:**
```text
29
```
**解题思路:** 先验证月份,再判断 2 月2 月内部嵌套判断闰年,其余月份判断 30 天或 31 天。
**参考代码:**
```cpp
#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。
**输入样例:**
```text
17 % 5
```
**输出样例:**
```text
2
```
**解题思路:** 先按运算符多层分支;进入除法或取模分支后再嵌套判断除数。
**参考代码:**
```cpp
#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.523.9 输出 `NORMAL`2427.9 输出 `HIGH`28 及以上输出 `VERY HIGH`
**输入格式:** 输入体重和身高两个实数。
**输出格式:** BMI 等级。
**数据范围:** `20≤weight≤300``1≤height≤2.5`
**输入样例:**
```text
60 1.70
```
**输出样例:**
```text
NORMAL
```
**解题思路:** 先计算 `weight/(height*height)`,再按从小到大的边界进行多层判断。
**参考代码:**
```cpp
#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。
**输入样例:**
```text
3 4 5
```
**输出样例:**
```text
SCALENE
RIGHT
```
**解题思路:** 先判断合法性;合法后分别进行边型判断和直角判断。直角判断需覆盖三条边分别为斜边的情况。
**参考代码:**
```cpp
#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 元15 千克每增加 1 千克加 3 元,不足 1 千克按 1 千克算;超过 5 千克的部分每千克加 5 元。偏远地区加 10 元,加急再加总价的 20%。
**输入格式:** 依次输入包裹重量、是否为偏远地区和是否加急;后两项用 0 或 1 表示。
**输出格式:** 运费,保留两位小数。
**数据范围:** `0<w≤100`
**输入样例:**
```text
6.2 1 1
```
**输出样例:**
```text
48.00
```
**解题思路:** 先向上取整重量并按档位计算,再依次处理偏远和加急条件。
**参考代码:**
```cpp
#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`
**输入格式:** 两个字符。
**输出格式:** 裁判结果。
**数据范围:** 任意可见字符。
**输入样例:**
```text
R S
```
**输出样例:**
```text
A
```
**解题思路:** 先检查两个手势是否合法;再判断平局;最后用三个获胜组合判断 A 是否获胜。
**参考代码:**
```cpp
#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`
**数据范围:** 平均分 `0100`,其余为非负整数,违纪用 0/1 表示。
**输入样例:**
```text
87 0 60 0
```
**输出样例:**
```text
SECOND
```
**解题思路:** 违纪是最高优先级;未违纪时按奖项从高到低判断,括号明确“且”“或”的组合。
**参考代码:**
```cpp
#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`,价格和评分为正整数。
**输入样例:**
```text
4
5 100 9
2 120 9
8 80 8
3 100 9
```
**输出样例:**
```text
3
```
**解题思路:** 第一优先级比较评分,第二优先级比较价格,第三优先级比较编号。
**参考代码:**
```cpp
#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综合录取规则【略难】
**题目描述:** 输入笔试、面试、体育三项成绩,以及是否有竞赛一等奖。任一成绩不在 0100 输出 `ERROR`。竞赛一等奖且笔试≥70 可直接录取否则笔试≥85 时面试≥80 且体育≥60 录取;笔试 7584 时面试≥90 且体育≥70 才录取;其他情况不录取。
**输入格式:** 依次输入笔试成绩、面试成绩、体育成绩和是否获得竞赛一等奖;最后一项用 0 或 1 表示。
**输出格式:** `ADMITTED``REJECTED``ERROR`
**数据范围:** 成绩可能为任意整数。
**输入样例:**
```text
78 92 75 0
```
**输出样例:**
```text
ADMITTED
```
**解题思路:** 先做数据合法性检查,再判断特殊录取,最后按笔试档位嵌套判断面试和体育条件。
**参考代码:**
```cpp
#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;
}
```
**易错提醒:** 数据检查、特殊规则、普通规则的优先级不能调换。