调整课次结构:前9节重新排序,新建第06课一维数组,后3节不变
This commit is contained in:
145
第09课-枚举模拟/教案-学生版.md
Normal file
145
第09课-枚举模拟/教案-学生版.md
Normal file
@@ -0,0 +1,145 @@
|
||||
# 第8课:枚举与模拟(三级工具降维)
|
||||
|
||||
> 等级说明:本课使用三级工具帮助解决一级、二级综合问题。
|
||||
|
||||
## 教学目标
|
||||
- 理解枚举算法的核心思想:列举所有可能,逐一验证
|
||||
- 掌握枚举优化的两个技巧:缩小范围、提前终止
|
||||
- 理解模拟算法的核心思想:按题目描述一步步翻译成代码
|
||||
|
||||
## 核心考点:枚举范围与模拟执行顺序
|
||||
|
||||
### 考什么
|
||||
枚举所有可能并逐一________,或按题目规则一步一步更新________。
|
||||
|
||||
### 必须理解
|
||||
枚举三步是:确定________、确定合法________、写出验证________。模拟时必须保持题目规定的________顺序。是否使用 `break`,取决于题目要________________。
|
||||
|
||||
### 核心写法
|
||||
```cpp
|
||||
for (int i = ________; i <= ________; i++) {
|
||||
if (____________________) {
|
||||
// 记录、计数或输出
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 1; i <= ________; i++) {
|
||||
// ____________________
|
||||
}
|
||||
```
|
||||
|
||||
### 常见错误
|
||||
- 枚举范围漏掉端点会怎样?________________
|
||||
- 什么情况下不能找到答案就 `break`?________________
|
||||
- 模拟步骤颠倒是否会影响答案?________
|
||||
|
||||
### 判断是否掌握
|
||||
- [ ] 我能确定候选变量和完整范围。
|
||||
- [ ] 我能写出验证条件。
|
||||
- [ ] 我能按正确顺序模拟状态变化。
|
||||
|
||||
---
|
||||
|
||||
## 课堂编程题
|
||||
|
||||
### 课堂1:鸡兔同笼【适中】
|
||||
|
||||
**题目描述:** 笼中只有鸡和兔。输入头数与脚数,输出鸡和兔的数量;没有合法方案时输出 `NONE`。
|
||||
|
||||
**输入格式:** 输入动物总数和脚的总数。
|
||||
|
||||
**输出格式:** 输出鸡的数量和兔的数量,或输出 `NONE`。
|
||||
|
||||
**数据范围:** 动物总数为 1~1000,脚数为非负整数。
|
||||
|
||||
**输入样例:**
|
||||
```text
|
||||
10 28
|
||||
```
|
||||
|
||||
**输出样例:**
|
||||
```text
|
||||
6 4
|
||||
```
|
||||
|
||||
**解题思路:** 枚举鸡的数量,兔的数量由总数减去鸡数得到,再验证脚数。
|
||||
|
||||
**易错提醒:** 枚举范围必须包含 0 和动物总数;题目只需一个方案,找到后可以结束循环。
|
||||
|
||||
### 课堂2:硬币组合【适中】
|
||||
|
||||
**题目描述:** 用 1 元、2 元和 5 元硬币凑出指定金额,要求硬币总数固定。输出所有方案,每行依次输出三种硬币数量。
|
||||
|
||||
**输入格式:** 输入目标金额和硬币总数。
|
||||
|
||||
**输出格式:** 输出全部合法方案;没有方案时输出 `NONE`。
|
||||
|
||||
**数据范围:** 目标金额和硬币总数均为 1~100。
|
||||
|
||||
**输入样例:**
|
||||
```text
|
||||
10 4
|
||||
```
|
||||
|
||||
**输出样例:**
|
||||
```text
|
||||
1 2 1
|
||||
```
|
||||
|
||||
**解题思路:** 枚举 1 元和 2 元硬币数量,5 元硬币数量由总数直接计算,再检查金额。
|
||||
|
||||
**易错提醒:** 第三种硬币无需再枚举;题目要求全部方案,找到后不能提前结束。
|
||||
|
||||
### 课堂3:斐波那契数列【适中】
|
||||
|
||||
**题目描述:** 数列前两项为 1,之后每项等于前两项之和。输入项数,输出前若干项。
|
||||
|
||||
**输入格式:** 输入需要输出的项数。
|
||||
|
||||
**输出格式:** 输出数列前若干项,以空格分隔。
|
||||
|
||||
**数据范围:** 项数为 1~45。
|
||||
|
||||
**输入样例:**
|
||||
```text
|
||||
6
|
||||
```
|
||||
|
||||
**输出样例:**
|
||||
```text
|
||||
1 1 2 3 5 8
|
||||
```
|
||||
|
||||
**解题思路:** 用两个变量保存连续两项;先计算下一项,再按顺序更新两个变量。
|
||||
|
||||
**易错提醒:** 更新顺序不能颠倒,必须先用旧值计算下一项。
|
||||
|
||||
### 课堂4:交通灯状态【适中】
|
||||
|
||||
**题目描述:** 交通灯按"绿灯 30 秒、黄灯 5 秒、红灯 25 秒"循环。第 1 秒为绿灯。输入秒数,输出当时颜色以及该颜色已经持续的秒数。
|
||||
|
||||
**输入格式:** 输入一个正整数,表示经过的秒数。
|
||||
|
||||
**输出格式:** 输出颜色和当前颜色已持续的秒数。
|
||||
|
||||
**数据范围:** 秒数不超过十亿。
|
||||
|
||||
**输入样例:**
|
||||
```text
|
||||
34
|
||||
```
|
||||
|
||||
**输出样例:**
|
||||
```text
|
||||
YELLOW 4
|
||||
```
|
||||
|
||||
**解题思路:** 一个周期共 60 秒,将时间映射到 1~60,再按三个区间判断。
|
||||
|
||||
**易错提醒:** 第 60 秒仍在本周期,第 61 秒才回到绿灯第 1 秒。
|
||||
|
||||
---
|
||||
|
||||
## 课后作业
|
||||
|
||||
> 请完成本课对应的课后作业,见编程题文件。
|
||||
227
第09课-枚举模拟/教案-教师版.md
Normal file
227
第09课-枚举模拟/教案-教师版.md
Normal file
@@ -0,0 +1,227 @@
|
||||
# 第8课:枚举与模拟(三级工具降维)
|
||||
|
||||
> 等级说明:枚举与模拟属于 GESP 三级知识。本课把它们作为工具,用来简化一级、二级的循环、分支与简单数学问题。
|
||||
|
||||
## 教学目标
|
||||
- 理解枚举算法的核心思想:列举所有可能,逐一验证
|
||||
- 掌握枚举优化的两个技巧:缩小范围、提前终止
|
||||
- 理解模拟算法的核心思想:按题目描述一步步翻译成代码
|
||||
|
||||
## 核心考点:枚举范围与模拟执行顺序
|
||||
|
||||
### 考什么
|
||||
枚举题要求列出所有可能答案并逐一验证;模拟题要求按照题目描述复现一个变化过程。两者都依赖清晰的范围、条件和执行顺序,常考输出满足条件的方案、计数或最终状态。
|
||||
|
||||
### 必须理解
|
||||
枚举包含三步:确定候选变量、确定合法范围、写出验证条件。范围必须覆盖所有可能答案,但可以利用题目约束缩小。找到答案后是否 `break`,取决于题目要第一个答案还是全部答案。模拟则要把文字规则拆成按顺序执行的动作,明确每一步读取旧状态还是更新后的状态;若多个变量应同时变化,不能让前一个更新意外影响后一个计算。
|
||||
|
||||
### 核心写法
|
||||
```cpp
|
||||
for (int candidate = lower; candidate <= upper; candidate++) {
|
||||
if (满足全部条件) {
|
||||
// 记录、计数或输出 candidate
|
||||
}
|
||||
}
|
||||
|
||||
for (int step = 1; step <= totalSteps; step++) {
|
||||
// 按题意顺序更新当前状态
|
||||
}
|
||||
```
|
||||
枚举是在“答案空间”中找;模拟是在“时间步骤”中走。先判断题目属于哪一种,再确定循环变量的含义。
|
||||
|
||||
### 常见错误
|
||||
- 枚举范围少一个端点,漏掉合法答案。
|
||||
- 未判断题目要全部解,找到第一个就错误 `break`。
|
||||
- 把模拟步骤顺序颠倒,得到不同状态。
|
||||
- 明明能由约束缩小范围,却枚举过多无效候选,造成超时。
|
||||
|
||||
### 判断是否掌握
|
||||
能指出循环变量代表候选答案还是执行步数,能给出完整上下界和验证条件,并能用手算前几步检查模拟更新顺序。
|
||||
|
||||
---
|
||||
|
||||
## 题目一:鸡兔同笼(枚举入门)
|
||||
|
||||
### 核心代码(一句话)
|
||||
> 枚举的核心:**`for` 循环遍历所有可能的答案**,用 `if` 判断是否满足条件,满足就输出。
|
||||
|
||||
### 自然语言思路
|
||||
笼子里有鸡和兔,一共 n 个头、m 只脚。鸡有 2 只脚,兔有 4 只脚。问鸡和兔各有几只?
|
||||
|
||||
第一步,鸡的数量可能是 0 到 n(因为总共 n 个头),让 `chicken` 从 0 循环到 n。
|
||||
第二步,兔的数量 = 总数 - 鸡数:`rabbit = n - chicken`。
|
||||
第三步,验证脚数:`chicken * 2 + rabbit * 4 == m`,如果成立,这就是答案。
|
||||
第四步,输出鸡和兔的数量。
|
||||
|
||||
> 枚举就像"地毯式搜索"——把所有可能性都试一遍,看哪个符合条件。
|
||||
|
||||
### 伪代码
|
||||
```
|
||||
1. 输入 n(头数), m(脚数)
|
||||
2. for chicken = 0 到 n:
|
||||
3. rabbit = n - chicken
|
||||
4. if chicken * 2 + rabbit * 4 == m:
|
||||
5. 输出 chicken 和 rabbit
|
||||
```
|
||||
|
||||
### 真实代码
|
||||
```cpp
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
|
||||
int main() {
|
||||
int n, m;
|
||||
cin >> n >> m;
|
||||
|
||||
for (int chicken = 0; chicken <= n; chicken++) {
|
||||
int rabbit = n - chicken;
|
||||
if (chicken * 2 + rabbit * 4 == m) {
|
||||
cout << "鸡:" << chicken << ",兔:" << rabbit << endl;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
### 注意点
|
||||
1. **枚举范围 0 到 n**:不要漏掉 0(可能全是兔子)和 n(可能全是鸡)。
|
||||
2. **兔的数量直接算**:因为鸡兔总数固定,所以兔 = n - 鸡,不需要再套一层循环枚举兔。这是"间接枚举"——少一个变量就少一层循环。
|
||||
3. **可能无解**:如果循环结束都没输出,说明数据有问题(比如输入 2 个头 100 只脚)。
|
||||
4. **脚数奇偶性判断**:实际上可以先用 `if (m % 2 != 0)` 快速判断无解(因为每只动物脚数都是偶数),但这是优化技巧,初学者先掌握枚举思路。
|
||||
|
||||
---
|
||||
|
||||
## 题目二:找完数(枚举进阶)
|
||||
|
||||
### 核心代码(一句话)
|
||||
> 完数判断的核心:**枚举所有小于 n 的正整数 i,如果 `n % i == 0`,i 就是 n 的因子,把因子累加起来**,最后比较和是否等于 n。
|
||||
|
||||
### 自然语言思路
|
||||
完数是指一个数等于它所有真因子(不包括自身)之和。比如 6 = 1 + 2 + 3,28 = 1 + 2 + 4 + 7 + 14。请找出 1000 以内的所有完数。
|
||||
|
||||
第一步,外层枚举:`for (n = 2; n <= 1000; n++)`,对每个 n 判断它是不是完数。
|
||||
第二步,对每个 n,用内层循环从 1 到 n-1 找它的因子:`if (n % i == 0)` 则 `sum += i`。
|
||||
第三步,遍历完所有因子后,`if (sum == n)` 则 n 是完数,输出。
|
||||
第四步,优化:找因子只需要搜到 `n/2`(因为大于 n/2 的数不可能是 n 的因子,除了 n 自身)。不过用 `sqrt(n)` 也行但要处理成对出现的情况。
|
||||
|
||||
### 伪代码
|
||||
```
|
||||
1. for n = 2 到 1000:
|
||||
2. sum = 0
|
||||
3. for i = 1 到 n-1:
|
||||
4. if n % i == 0:
|
||||
5. sum += i
|
||||
6. if sum == n:
|
||||
7. 输出 n
|
||||
```
|
||||
|
||||
### 真实代码
|
||||
```cpp
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
|
||||
int main() {
|
||||
for (int n = 2; n <= 1000; n++) {
|
||||
int sum = 0;
|
||||
// 找因子并累加(优化:只需搜到 n/2)
|
||||
for (int i = 1; i <= n / 2; i++) {
|
||||
if (n % i == 0) {
|
||||
sum += i;
|
||||
}
|
||||
}
|
||||
if (sum == n) {
|
||||
cout << n << " "; // 输出:6 28 496
|
||||
}
|
||||
}
|
||||
cout << endl;
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
### 注意点
|
||||
1. **sum 必须在内层循环前清零**:每次换一个 n,sum 要重新从 0 开始累加,忘了清零会累加前面所有数的结果。
|
||||
2. **优化枚举范围**:因子搜索范围从 `n-1` 优化到 `n/2`,因为大于 n/2 且小于 n 的数不可能是 n 的因子。
|
||||
3. **1 不是完数**:1 的真因子之和是 0(1 没有真因子),不等于 1,所以从 2 开始枚举。
|
||||
4. **1000 以内的完数只有 3 个**:6、28、496。如果输出不止这些,说明逻辑有误。
|
||||
|
||||
---
|
||||
|
||||
## 题目三:斐波那契数列(模拟算法)
|
||||
|
||||
### 核心代码(一句话)
|
||||
> 模拟的核心:**按照规则,用变量记录当前状态,一步一步更新**。斐波那契的规则是:**第三项 = 前两项之和**,用 `a, b` 两个变量滚动更新即可。
|
||||
|
||||
### 自然语言思路
|
||||
斐波那契数列:1, 1, 2, 3, 5, 8, 13, 21, 34, 55……每一项等于前两项之和。输入 n,输出前 n 项。
|
||||
|
||||
第一步,用两个变量 `a` 和 `b` 分别记录"当前项"和"下一项",初始 `a = 1, b = 1`。
|
||||
第二步,循环 n 次,每次输出 `a`(当前项),然后计算新的两项:`temp = a + b; a = b; b = temp;`。
|
||||
第三步,模拟过程:a=1,b=1 → 输出1 → a=1,b=2 → 输出1 → a=2,b=3 → 输出2 → a=3,b=5 → 输出3 …… 就像"滚动更新"。
|
||||
|
||||
> 模拟算法 = 读懂题目规则 → 翻译成代码。不需要聪明,只需要认真。
|
||||
|
||||
### 伪代码
|
||||
```
|
||||
1. 输入 n
|
||||
2. a = 1, b = 1
|
||||
3. for i = 1 到 n:
|
||||
4. 输出 a
|
||||
5. temp = a + b
|
||||
6. a = b
|
||||
7. b = temp
|
||||
```
|
||||
|
||||
### 真实代码
|
||||
```cpp
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
|
||||
int main() {
|
||||
int n;
|
||||
cin >> n;
|
||||
|
||||
int a = 1, b = 1;
|
||||
for (int i = 1; i <= n; i++) {
|
||||
cout << a << " ";
|
||||
int temp = a + b; // 计算下一项
|
||||
a = b; // a 前进
|
||||
b = temp; // b 前进
|
||||
}
|
||||
cout << endl;
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
### 注意点
|
||||
1. **更新顺序不能错**:必须先算 `temp = a + b`(基于旧值),再更新 a 和 b。如果先改 a 再算 `a + b`,用的就是新的 a 了,结果全乱。
|
||||
2. **n=1 和 n=2 的情况**:循环 1 次输出 1,循环 2 次输出 "1 1"。代码不用特殊处理,天然正确。
|
||||
3. **数据范围**:斐波那契数列增长很快,第 46 项就超过 20 亿了。如果 n 大到 50+,要用 `long long` 替代 `int`(因为 `int` 最大约 21 亿)。
|
||||
4. **另一种写法 — 数组存储**:`int fib[100]; fib[1]=1; fib[2]=1; fib[i]=fib[i-1]+fib[i-2];` 更直观但占内存。
|
||||
|
||||
---
|
||||
|
||||
## 枚举 vs 模拟 对比
|
||||
|
||||
| 对比维度 | 枚举 | 模拟 |
|
||||
|----------|------|------|
|
||||
| 核心思路 | 列举所有可能 → 逐一验证 | 按照规则 → 逐步执行 |
|
||||
| 适用场景 | 答案范围有限、可以逐一验证 | 题目有明确的步骤描述 |
|
||||
| 典型题目 | 鸡兔同笼、百钱百鸡、完数 | 斐波那契、杨辉三角、日期计算 |
|
||||
| 优化方向 | 缩小范围、提前终止、剪枝 | 找规律、用公式替代逐步模拟 |
|
||||
|
||||
---
|
||||
|
||||
## 本课打油诗
|
||||
|
||||
> 枚举就是全试过,循环里面 if 判断。
|
||||
> 范围要想清边界,找到答案就停站。
|
||||
> 模拟照着步骤走,题目说啥咱干啥。
|
||||
> 变量更新看顺序,一步一步不出错。
|
||||
|
||||
---
|
||||
|
||||
## 课后作业
|
||||
1. 找出 1000 以内所有的"亲密数对"(a 的因子之和等于 b,b 的因子之和等于 a,且 a ≠ b)
|
||||
2. 百钱百鸡:公鸡 5 元/只,母鸡 3 元/只,小鸡 1 元 3 只。用 100 元买 100 只鸡,输出所有方案
|
||||
3. 输出杨辉三角的前 n 行
|
||||
4. 输出所有三位数的水仙花数(如 153 = 1³ + 5³ + 3³)
|
||||
676
第09课-枚举模拟/编程题-教师版.md
Normal file
676
第09课-枚举模拟/编程题-教师版.md
Normal file
@@ -0,0 +1,676 @@
|
||||
# 第8课编程题(教师版)
|
||||
|
||||
## 本课知识点覆盖表
|
||||
|
||||
| 核心知识点 | 等级定位 | 对应课堂题 |
|
||||
|---|---|---|
|
||||
| 单变量枚举、范围与验证条件 | 三级工具,服务一二级循环分支 | 课堂1 |
|
||||
| 双变量枚举、利用约束缩小范围 | 三级工具,服务简单数学 | 课堂2 |
|
||||
| 状态变量、按顺序更新 | 三级工具,服务循环模拟 | 课堂3 |
|
||||
| 周期过程模拟、取模与分支 | 三级工具,服务综合判断 | 课堂4 |
|
||||
|
||||
## 一、课堂练习(4题)
|
||||
|
||||
### 课堂1:鸡兔同笼【适中】
|
||||
|
||||
**题目描述:** 笼中只有鸡和兔。输入头数与脚数,输出鸡和兔的数量;没有合法方案时输出 `NONE`。
|
||||
|
||||
**输入格式:** 输入动物总数和脚的总数。
|
||||
|
||||
**输出格式:** 输出鸡的数量和兔的数量,或输出 `NONE`。
|
||||
|
||||
**数据范围:** 动物总数为 1~1000,脚数为非负整数。
|
||||
|
||||
**输入样例:**
|
||||
```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`。
|
||||
|
||||
**数据范围:** 目标金额和硬币总数均为 1~100。
|
||||
|
||||
**输入样例:**
|
||||
```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,之后每项等于前两项之和。输入项数,输出前若干项。
|
||||
|
||||
**输入格式:** 输入需要输出的项数。
|
||||
|
||||
**输出格式:** 输出数列前若干项,以空格分隔。
|
||||
|
||||
**数据范围:** 项数为 1~45。
|
||||
|
||||
**输入样例:**
|
||||
```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 秒,将时间映射到 1~60,再按三个区间判断。
|
||||
|
||||
**参考代码:**
|
||||
```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:小球反弹高度【简单】
|
||||
|
||||
**题目描述:** 小球从指定高度落下,每次反弹到上一次高度的一半。输入初始高度和反弹次数,输出最后一次反弹高度,保留两位小数。
|
||||
|
||||
**输入格式:** 输入初始高度和反弹次数。
|
||||
|
||||
**输出格式:** 输出最后一次反弹高度,保留两位小数。
|
||||
|
||||
**数据范围:** 初始高度为正数,反弹次数为 0~30。
|
||||
|
||||
**输入样例:**
|
||||
```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。输入若干条指令,正数表示向右移动,负数表示向左移动。输出最终位置。
|
||||
|
||||
**输入格式:** 第一行输入指令数量;第二行输入每条指令的移动距离。
|
||||
|
||||
**输出格式:** 输出机器人最终位置。
|
||||
|
||||
**数据范围:** 指令数量为 1~100,每次移动距离绝对值不超过一千。
|
||||
|
||||
**输入样例:**
|
||||
```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`。
|
||||
|
||||
**数据范围:** 输入范围位于 100~999。
|
||||
|
||||
**输入样例:**
|
||||
```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 倍,并按从小到大输出。
|
||||
|
||||
**输入格式:** 本题没有输入。
|
||||
|
||||
**输出格式:** 输出全部满足条件的两位数。
|
||||
|
||||
**数据范围:** 枚举 10~99。
|
||||
|
||||
**输入样例:**
|
||||
```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:日期的下一天【中等】
|
||||
|
||||
**题目描述:** 输入一个日期,输出下一天。需要正确处理月末、年末和闰年二月。
|
||||
|
||||
**输入格式:** 输入年份、月份和日期。
|
||||
|
||||
**输出格式:** 输出下一天的年份、月份和日期。
|
||||
|
||||
**数据范围:** 输入保证是合法日期,年份为 1~9999。
|
||||
|
||||
**输入样例:**
|
||||
```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 分。输入每场进球数和失球数,输出总积分及胜、平、负场次。
|
||||
|
||||
**输入格式:** 第一行输入比赛场数;随后每行输入一场比赛的进球数和失球数。
|
||||
|
||||
**输出格式:** 依次输出总积分、胜场、平场和负场。
|
||||
|
||||
**数据范围:** 比赛场数为 1~100,进球数和失球数为非负整数。
|
||||
|
||||
**输入样例:**
|
||||
```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 号开始依次报数,报到指定数字的人离开,继续从下一人报数,直到只剩一人。输出最后留下的编号。
|
||||
|
||||
**输入格式:** 输入同学人数和离开所对应的报数。
|
||||
|
||||
**输出格式:** 输出最后留下的同学编号。
|
||||
|
||||
**数据范围:** 同学人数为 1~100,报数为 1~100。
|
||||
|
||||
**输入样例:**
|
||||
```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 元商品。余额足够才扣款并增加购买次数,否则记录一次失败。输出最终余额、成功购买次数和失败次数。
|
||||
|
||||
**输入格式:** 第一行输入操作数量;第二行输入所有操作代码。
|
||||
|
||||
**输出格式:** 依次输出最终余额、成功购买次数和失败次数。
|
||||
|
||||
**数据范围:** 操作数量为 1~1000,投入金额为 1~100。
|
||||
|
||||
**输入样例:**
|
||||
```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;
|
||||
}
|
||||
```
|
||||
|
||||
**易错提醒:** 失败购买不能扣除余额;操作必须严格按输入顺序处理。
|
||||
Reference in New Issue
Block a user