调整课次结构:前9节重新排序,新建第06课一维数组,后3节不变

This commit is contained in:
chengzi
2026-07-03 15:27:11 +08:00
parent 30f803784a
commit b973fb7825
29 changed files with 1301 additions and 13 deletions

View File

@@ -0,0 +1,676 @@
# 第8课编程题教师版
## 本课知识点覆盖表
| 核心知识点 | 等级定位 | 对应课堂题 |
|---|---|---|
| 单变量枚举、范围与验证条件 | 三级工具,服务一二级循环分支 | 课堂1 |
| 双变量枚举、利用约束缩小范围 | 三级工具,服务简单数学 | 课堂2 |
| 状态变量、按顺序更新 | 三级工具,服务循环模拟 | 课堂3 |
| 周期过程模拟、取模与分支 | 三级工具,服务综合判断 | 课堂4 |
## 一、课堂练习4题
### 课堂1鸡兔同笼【适中】
**题目描述:** 笼中只有鸡和兔。输入头数与脚数,输出鸡和兔的数量;没有合法方案时输出 `NONE`
**输入格式:** 输入动物总数和脚的总数。
**输出格式:** 输出鸡的数量和兔的数量,或输出 `NONE`
**数据范围:** 动物总数为 11000脚数为非负整数。
**输入样例:**
```text
10 28
```
**输出样例:**
```text
6 4
```
**解题思路:** 枚举鸡的数量,兔的数量由总数减去鸡数得到,再验证脚数。
**参考代码:**
```cpp
#include <iostream>
using namespace std;
int main() {
int heads, feet;
cin >> heads >> feet;
bool found = false;
for (int chicken = 0; chicken <= heads; chicken++) {
int rabbit = heads - chicken;
if (chicken * 2 + rabbit * 4 == feet) {
cout << chicken << " " << rabbit;
found = true;
break;
}
}
if (!found) cout << "NONE";
return 0;
}
```
**易错提醒:** 枚举范围必须包含 0 和动物总数;题目只需一个方案,找到后可以结束循环。
### 课堂2硬币组合【适中】
**题目描述:** 用 1 元、2 元和 5 元硬币凑出指定金额,要求硬币总数固定。输出所有方案,每行依次输出三种硬币数量。
**输入格式:** 输入目标金额和硬币总数。
**输出格式:** 输出全部合法方案;没有方案时输出 `NONE`
**数据范围:** 目标金额和硬币总数均为 1100。
**输入样例:**
```text
10 4
```
**输出样例:**
```text
1 2 1
```
**解题思路:** 枚举 1 元和 2 元硬币数量5 元硬币数量由总数直接计算,再检查金额。
**参考代码:**
```cpp
#include <iostream>
using namespace std;
int main() {
int money, total;
cin >> money >> total;
bool found = false;
for (int one = 0; one <= total; one++) {
for (int two = 0; two + one <= total; two++) {
int five = total - one - two;
if (one + two * 2 + five * 5 == money) {
cout << one << " " << two << " " << five << "\n";
found = true;
}
}
}
if (!found) cout << "NONE";
return 0;
}
```
**易错提醒:** 第三种硬币无需再枚举;题目要求全部方案,找到后不能提前结束。
### 课堂3斐波那契数列【适中】
**题目描述:** 数列前两项为 1之后每项等于前两项之和。输入项数输出前若干项。
**输入格式:** 输入需要输出的项数。
**输出格式:** 输出数列前若干项,以空格分隔。
**数据范围:** 项数为 145。
**输入样例:**
```text
6
```
**输出样例:**
```text
1 1 2 3 5 8
```
**解题思路:** 用两个变量保存连续两项;先计算下一项,再按顺序更新两个变量。
**参考代码:**
```cpp
#include <iostream>
using namespace std;
int main() {
int n;
long long first = 1, second = 1;
cin >> n;
for (int i = 1; i <= n; i++) {
if (i > 1) cout << " ";
cout << first;
long long next = first + second;
first = second;
second = next;
}
return 0;
}
```
**易错提醒:** 更新顺序不能颠倒,必须先用旧值计算下一项。
### 课堂4交通灯状态【适中】
**题目描述:** 交通灯按“绿灯 30 秒、黄灯 5 秒、红灯 25 秒”循环。第 1 秒为绿灯。输入秒数,输出当时颜色以及该颜色已经持续的秒数。
**输入格式:** 输入一个正整数,表示经过的秒数。
**输出格式:** 输出颜色和当前颜色已持续的秒数。
**数据范围:** 秒数不超过十亿。
**输入样例:**
```text
34
```
**输出样例:**
```text
YELLOW 4
```
**解题思路:** 一个周期共 60 秒,将时间映射到 160再按三个区间判断。
**参考代码:**
```cpp
#include <iostream>
using namespace std;
int main() {
long long second;
cin >> second;
int position = (second - 1) % 60 + 1;
if (position <= 30)
cout << "GREEN " << position;
else if (position <= 35)
cout << "YELLOW " << position - 30;
else
cout << "RED " << position - 35;
return 0;
}
```
**易错提醒:** 第 60 秒仍在本周期,第 61 秒才回到绿灯第 1 秒。
## 二、课后作业3题
### 课后1满足条件的倍数【简单】
**题目描述:** 输出指定范围内所有能被 3 整除但不能被 5 整除的整数。
**输入格式:** 输入范围的左端点和右端点。
**输出格式:** 按从小到大输出所有满足条件的整数;没有则输出 `NONE`
**数据范围:** 左端点不大于右端点,绝对值不超过一万。
**输入样例:**
```text
1 20
```
**输出样例:**
```text
3 6 9 12 18
```
**解题思路:** 枚举范围内每个整数,用一个条件验证。
**参考代码:**
```cpp
#include <iostream>
using namespace std;
int main() {
int left, right;
bool found = false;
cin >> left >> right;
for (int number = left; number <= right; number++) {
if (number % 3 == 0 && number % 5 != 0) {
if (found) cout << " ";
cout << number;
found = true;
}
}
if (!found) cout << "NONE";
return 0;
}
```
**易错提醒:** 范围包含两个端点;两个条件必须同时满足。
### 课后2小球反弹高度【简单】
**题目描述:** 小球从指定高度落下,每次反弹到上一次高度的一半。输入初始高度和反弹次数,输出最后一次反弹高度,保留两位小数。
**输入格式:** 输入初始高度和反弹次数。
**输出格式:** 输出最后一次反弹高度,保留两位小数。
**数据范围:** 初始高度为正数,反弹次数为 030。
**输入样例:**
```text
100 3
```
**输出样例:**
```text
12.50
```
**解题思路:** 每次循环把当前高度除以 2按步骤模拟。
**参考代码:**
```cpp
#include <iostream>
#include <iomanip>
using namespace std;
int main() {
double height;
int times;
cin >> height >> times;
for (int i = 1; i <= times; i++) height /= 2;
cout << fixed << setprecision(2) << height;
return 0;
}
```
**易错提醒:** 反弹 0 次时高度保持初始值。
### 课后3机器人走直线【简单】
**题目描述:** 机器人初始位置为 0。输入若干条指令正数表示向右移动负数表示向左移动。输出最终位置。
**输入格式:** 第一行输入指令数量;第二行输入每条指令的移动距离。
**输出格式:** 输出机器人最终位置。
**数据范围:** 指令数量为 1100每次移动距离绝对值不超过一千。
**输入样例:**
```text
5
3 -2 4 -6 1
```
**输出样例:**
```text
0
```
**解题思路:** 用一个变量记录位置,按输入顺序累加每次移动。
**参考代码:**
```cpp
#include <iostream>
using namespace std;
int main() {
int n, position = 0;
cin >> n;
for (int i = 0; i < n; i++) {
int move;
cin >> move;
position += move;
}
cout << position;
return 0;
}
```
**易错提醒:** 负数已经表示向左,不需要再额外减一次。
## 三、扩展练习7题
### 扩展1三位水仙花数【基础综合】
**题目描述:** 输出指定范围内所有三位水仙花数。水仙花数等于各位数字立方和。
**输入格式:** 输入范围的左端点和右端点。
**输出格式:** 输出所有水仙花数;没有则输出 `NONE`
**数据范围:** 输入范围位于 100999。
**输入样例:**
```text
100 400
```
**输出样例:**
```text
153 370 371
```
**解题思路:** 枚举每个三位数,拆出百位、十位和个位后验证。
**参考代码:**
```cpp
#include <iostream>
using namespace std;
int main() {
int left, right;
bool found = false;
cin >> left >> right;
for (int number = left; number <= right; number++) {
int a = number / 100;
int b = number / 10 % 10;
int c = number % 10;
if (a * a * a + b * b * b + c * c * c == number) {
if (found) cout << " ";
cout << number;
found = true;
}
}
if (!found) cout << "NONE";
return 0;
}
```
**易错提醒:** 十位数字应先除以 10 再取余数。
### 扩展2百钱买百鸡【中等】
**题目描述:** 公鸡每只 5 元,母鸡每只 3 元,小鸡 3 只 1 元。用 100 元恰好买 100 只鸡,输出全部方案。
**输入格式:** 本题没有输入。
**输出格式:** 每行依次输出公鸡、母鸡和小鸡数量。
**数据范围:** 三种鸡的数量均为非负整数。
**输入样例:**
```text
```
**输出样例:**
```text
0 25 75
4 18 78
8 11 81
12 4 84
```
**解题思路:** 枚举公鸡和母鸡,小鸡由总数计算;为避免小数,用“小鸡数量能被 3 整除”验证价格。
**参考代码:**
```cpp
#include <iostream>
using namespace std;
int main() {
for (int rooster = 0; rooster <= 20; rooster++) {
for (int hen = 0; hen <= 33; hen++) {
int chick = 100 - rooster - hen;
if (chick >= 0 && chick % 3 == 0 &&
rooster * 5 + hen * 3 + chick / 3 == 100) {
cout << rooster << " " << hen << " " << chick << "\n";
}
}
}
return 0;
}
```
**易错提醒:** 小鸡数量必须非负且能被 3 整除。
### 扩展3数字谜【中等】
**题目描述:** 找出所有两位数,使它等于各位数字之和的 4 倍,并按从小到大输出。
**输入格式:** 本题没有输入。
**输出格式:** 输出全部满足条件的两位数。
**数据范围:** 枚举 1099。
**输入样例:**
```text
```
**输出样例:**
```text
12 24 36 48
```
**解题思路:** 枚举两位数并拆分十位和个位,验证等式。
**参考代码:**
```cpp
#include <iostream>
using namespace std;
int main() {
bool first = true;
for (int number = 10; number <= 99; number++) {
int tens = number / 10;
int ones = number % 10;
if (number == 4 * (tens + ones)) {
if (!first) cout << " ";
cout << number;
first = false;
}
}
return 0;
}
```
**易错提醒:** 枚举顺序已经从小到大,不需要任何排序。
### 扩展4日期的下一天【中等】
**题目描述:** 输入一个日期,输出下一天。需要正确处理月末、年末和闰年二月。
**输入格式:** 输入年份、月份和日期。
**输出格式:** 输出下一天的年份、月份和日期。
**数据范围:** 输入保证是合法日期,年份为 19999。
**输入样例:**
```text
2024 2 29
```
**输出样例:**
```text
2024 3 1
```
**解题思路:** 先根据月份和闰年确定本月天数,日期加一后按顺序处理月进位和年进位。
**参考代码:**
```cpp
#include <iostream>
using namespace std;
int main() {
int year, month, day;
cin >> year >> month >> day;
int days;
if (month == 2) {
bool leap = year % 400 == 0 ||
(year % 4 == 0 && year % 100 != 0);
days = leap ? 29 : 28;
} else if (month == 4 || month == 6 ||
month == 9 || month == 11) {
days = 30;
} else {
days = 31;
}
day++;
if (day > days) {
day = 1;
month++;
if (month > 12) {
month = 1;
year++;
}
}
cout << year << " " << month << " " << day;
return 0;
}
```
**易错提醒:** 必须先处理日期进位,再处理月份和年份进位。
### 扩展5比赛积分模拟【中等】
**题目描述:** 一支球队进行若干场比赛,胜得 3 分、平得 1 分、负得 0 分。输入每场进球数和失球数,输出总积分及胜、平、负场次。
**输入格式:** 第一行输入比赛场数;随后每行输入一场比赛的进球数和失球数。
**输出格式:** 依次输出总积分、胜场、平场和负场。
**数据范围:** 比赛场数为 1100进球数和失球数为非负整数。
**输入样例:**
```text
3
2 1
0 0
1 3
```
**输出样例:**
```text
4 1 1 1
```
**解题思路:** 按场次模拟,根据比分三分支更新积分和统计量。
**参考代码:**
```cpp
#include <iostream>
using namespace std;
int main() {
int n, points = 0, win = 0, draw = 0, lose = 0;
cin >> n;
for (int i = 0; i < n; i++) {
int scored, conceded;
cin >> scored >> conceded;
if (scored > conceded) {
points += 3;
win++;
} else if (scored == conceded) {
points++;
draw++;
} else {
lose++;
}
}
cout << points << " " << win << " " << draw << " " << lose;
return 0;
}
```
**易错提醒:** 三种比赛结果互斥,使用多层分支。
### 扩展6约瑟夫报数简化版【略难】
**题目描述:** 若干名同学围成一圈,从 1 号开始依次报数,报到指定数字的人离开,继续从下一人报数,直到只剩一人。输出最后留下的编号。
**输入格式:** 输入同学人数和离开所对应的报数。
**输出格式:** 输出最后留下的同学编号。
**数据范围:** 同学人数为 1100报数为 1100。
**输入样例:**
```text
5 3
```
**输出样例:**
```text
4
```
**解题思路:** 用数组记录是否仍在圈中,循环移动当前位置,只对未离开的人计数,报到指定数字时标记离开。
**参考代码:**
```cpp
#include <iostream>
using namespace std;
int main() {
int n, limit;
bool alive[101] = {false};
cin >> n >> limit;
for (int i = 1; i <= n; i++) alive[i] = true;
int remaining = n, position = 0, count = 0;
while (remaining > 1) {
position = position % n + 1;
if (!alive[position]) continue;
count++;
if (count == limit) {
alive[position] = false;
remaining--;
count = 0;
}
}
for (int i = 1; i <= n; i++)
if (alive[i]) cout << i;
return 0;
}
```
**易错提醒:** 离开的人不再参与报数;位置到末尾后要回到 1 号。
### 扩展7自动售货机【略难】
**题目描述:** 售货机初始余额为 0。依次处理若干操作正数表示投入金额-1 表示购买 3 元商品;-2 表示购买 5 元商品。余额足够才扣款并增加购买次数,否则记录一次失败。输出最终余额、成功购买次数和失败次数。
**输入格式:** 第一行输入操作数量;第二行输入所有操作代码。
**输出格式:** 依次输出最终余额、成功购买次数和失败次数。
**数据范围:** 操作数量为 11000投入金额为 1100。
**输入样例:**
```text
7
5 -1 -2 8 -2 -1 1
```
**输出样例:**
```text
3 3 1
```
**解题思路:** 按输入顺序模拟。投入金额直接增加余额;购买操作先确定价格,再判断余额是否足够。
**参考代码:**
```cpp
#include <iostream>
using namespace std;
int main() {
int n, balance = 0, success = 0, failure = 0;
cin >> n;
for (int i = 0; i < n; i++) {
int operation;
cin >> operation;
if (operation > 0) {
balance += operation;
} else {
int price = (operation == -1) ? 3 : 5;
if (balance >= price) {
balance -= price;
success++;
} else {
failure++;
}
}
}
cout << balance << " " << success << " " << failure;
return 0;
}
```
**易错提醒:** 失败购买不能扣除余额;操作必须严格按输入顺序处理。