682 lines
18 KiB
Markdown
682 lines
18 KiB
Markdown
# 第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 <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`。
|
||
|
||
**输入样例:**
|
||
```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`,分数为 `0~100`。
|
||
|
||
**输入样例:**
|
||
```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`,编号互不相同,分数为 `0~100`。
|
||
|
||
**输入样例:**
|
||
```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:成绩等级【简单】
|
||
|
||
**题目描述:** 输入成绩: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 <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.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 <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 元;1~5 千克每增加 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`。
|
||
|
||
**数据范围:** 平均分 `0~100`,其余为非负整数,违纪用 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:综合录取规则【略难】
|
||
|
||
**题目描述:** 输入笔试、面试、体育三项成绩,以及是否有竞赛一等奖。任一成绩不在 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 <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;
|
||
}
|
||
```
|
||
|
||
**易错提醒:** 数据检查、特殊规则、普通规则的优先级不能调换。
|