Files
project1/第04课-C++自带函数与数学处理/编程题-教师版.md

633 lines
14 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.
# 第1课编程题教师版
## 本课知识点覆盖表
| 核心知识点 | GESP等级 | 对应课堂题 |
|---|---|---|
| `sqrt``pow``abs``<cmath>` | 一级巩固/二级拓展 | 课堂1 |
| `max``min``swap``<algorithm>` | 二级 | 课堂2 |
| `max``min` 综合应用 | 二级 | 课堂3 |
| `isalpha``isdigit``islower``isupper``tolower``toupper` | 一级/二级 | 课堂4 |
> 难度均为本课内部的相对难度。参考程序采用 C++17。
## 一、课堂练习4题
### 课堂1三点中最近的一对【适中】
**题目描述:** 输入平面上三个点的坐标,求三对点之间的最短距离,结果保留两位小数。要求使用 `sqrt``pow``min`
**输入格式:** 输入六个实数,依次表示三个点的横坐标和纵坐标。
**输出格式:** 输出最短距离,保留两位小数。
**数据范围:** 每个坐标的绝对值不超过 1000。
**输入样例:**
```text
0 0 3 4 0 2
```
**输出样例:**
```text
2.00
```
**解题思路:** 用勾股定理分别求出三段距离,再用 `min` 取最小值。
**参考代码:**
```cpp
#include <iostream>
#include <cmath>
#include <algorithm>
#include <iomanip>
using namespace std;
double distance(double x1, double y1, double x2, double y2) {
return sqrt(pow(x1 - x2, 2) + pow(y1 - y2, 2));
}
int main() {
double x1, y1, x2, y2, x3, y3;
cin >> x1 >> y1 >> x2 >> y2 >> x3 >> y3;
double d1 = distance(x1, y1, x2, y2);
double d2 = distance(x1, y1, x3, y3);
double d3 = distance(x2, y2, x3, y3);
cout << fixed << setprecision(2) << min(d1, min(d2, d3));
return 0;
}
```
**易错提醒:** `sqrt` 返回浮点数;格式化输出需要包含 `<iomanip>`
### 课堂2整理三个数【适中】
**题目描述:** 输入三个整数,第一行输出最大值和最小值;再使用 `swap` 将三个变量调整为升序,第二行输出调整结果。
**输入格式:** 输入三个整数。
**输出格式:** 第一行输出最大值和最小值;第二行输出升序结果。
**数据范围:** `-10^9≤a,b,c≤10^9`
**输入样例:**
```text
8 2 5
```
**输出样例:**
```text
8 2
2 5 8
```
**解题思路:** 用嵌套的 `max``min` 求最值;再进行三次相邻比较,需要时调用 `swap`
**参考代码:**
```cpp
#include <iostream>
#include <algorithm>
using namespace std;
int main() {
int a, b, c;
cin >> a >> b >> c;
cout << max(a, max(b, c)) << " " << min(a, min(b, c)) << "\n";
if (a > b) swap(a, b);
if (b > c) swap(b, c);
if (a > b) swap(a, b);
cout << a << " " << b << " " << c;
return 0;
}
```
**易错提醒:** `swap` 的参数必须是两个变量,不能传入 `a+b` 这样的表达式。
### 课堂3去掉最高分和最低分【适中】
**题目描述:** 输入若干个评委分数,去掉一个最高分和一个最低分,输出剩余分数之和。不得使用排序。
**输入格式:** 第一行输入评委人数;第二行输入所有评委给出的分数。
**输出格式:** 输出剩余分数之和。
**数据范围:** `3≤n≤100`,分数为 `0100`
**输入样例:**
```text
5
9 7 10 8 6
```
**输出样例:**
```text
24
```
**解题思路:** 遍历时同时计算总分、最高分和最低分,最后用总分减去两个极值。
**参考代码:**
```cpp
#include <iostream>
#include <algorithm>
using namespace std;
int main() {
int n, score, sum = 0, biggest, smallest;
cin >> n;
cin >> score;
sum = biggest = smallest = score;
for (int i = 1; i < n; i++) {
cin >> score;
sum += score;
biggest = max(biggest, score);
smallest = min(smallest, score);
}
cout << sum - biggest - smallest;
return 0;
}
```
**易错提醒:** 最高分和最低分要用第一个合法分数初始化;即使最高分重复,也只去掉一个。
### 课堂4字符身份证【适中】
**题目描述:** 输入一个可见字符。若为字母,输出 `LETTER` 和相反大小写的字符;若为数字,输出 `DIGIT`;否则输出 `OTHER`
**输入格式:** 一个可见字符。
**输出格式:** 按题目要求输出。
**数据范围:** 标准 ASCII 可见字符。
**输入样例:**
```text
G
```
**输出样例:**
```text
LETTER g
```
**解题思路:**`isalpha``isdigit` 分类,用 `islower``isupper` 判断大小写,再调用 `toupper``tolower` 转换。
**参考代码:**
```cpp
#include <iostream>
#include <cctype>
using namespace std;
int main() {
char c;
cin >> c;
if (isalpha(c)) {
cout << "LETTER ";
if (islower(c)) cout << (char)toupper(c);
else if (isupper(c)) cout << (char)tolower(c);
} else if (isdigit(c)) {
cout << "DIGIT";
} else {
cout << "OTHER";
}
return 0;
}
```
**易错提醒:** `tolower``toupper` 返回的是字符编码,输出字符时应转换为 `char`
## 二、课后作业3题
### 课后1离原点的距离【简单】
**题目描述:** 输入点 `(x,y)`,输出它到原点的距离,保留两位小数。
**输入格式:** 输入两个实数,依次表示横坐标和纵坐标。
**输出格式:** 距离,保留两位小数。
**数据范围:** 坐标绝对值不超过 1000。
**输入样例:**
```text
3 4
```
**输出样例:**
```text
5.00
```
**解题思路:** 根据勾股定理计算 `sqrt(pow(x,2)+pow(y,2))`
**参考代码:**
```cpp
#include <iostream>
#include <cmath>
#include <iomanip>
using namespace std;
int main() {
double x, y;
cin >> x >> y;
cout << fixed << setprecision(2)
<< sqrt(pow(x, 2) + pow(y, 2));
return 0;
}
```
**易错提醒:** 不要忘记 `<cmath>``<iomanip>`
### 课后2两数差的绝对值【简单】
**题目描述:** 输入两个整数,输出它们差的绝对值。
**输入格式:** 输入两个整数。
**输出格式:** 输出 `|a-b|`
**数据范围:** 两数绝对值不超过 10000。
**输入样例:**
```text
3 9
```
**输出样例:**
```text
6
```
**解题思路:** 直接调用 `abs(a-b)`
**参考代码:**
```cpp
#include <iostream>
#include <cmath>
using namespace std;
int main() {
int a, b;
cin >> a >> b;
cout << abs(a - b);
return 0;
}
```
**易错提醒:** 先求差再取绝对值,不要误写成 `abs(a)-abs(b)`
### 课后3数字还是字母【简单】
**题目描述:** 输入一个字符。是数字输出 `1`,是字母输出 `2`,其他字符输出 `0`
**输入格式:** 一个字符。
**输出格式:** 一个整数。
**数据范围:** 标准 ASCII 可见字符。
**输入样例:**
```text
8
```
**输出样例:**
```text
1
```
**解题思路:** 依次调用 `isdigit``isalpha`
**参考代码:**
```cpp
#include <iostream>
#include <cctype>
using namespace std;
int main() {
char c;
cin >> c;
if (isdigit(c)) cout << 1;
else if (isalpha(c)) cout << 2;
else cout << 0;
return 0;
}
```
**易错提醒:** 字符数字 `'8'` 与整数 `8` 不同。
## 三、扩展练习7题
### 扩展1正方形对角线【基础综合】
**题目描述:** 输入正方形边长,输出对角线长度,保留三位小数。
**输入格式:** 输入一个正实数,表示正方形的边长。
**输出格式:** 对角线长度。
**数据范围:** `0<a≤10000`
**输入样例:**
```text
2
```
**输出样例:**
```text
2.828
```
**解题思路:** 对角线为 `sqrt(2)*a`
**参考代码:**
```cpp
#include <iostream>
#include <cmath>
#include <iomanip>
using namespace std;
int main() {
double a;
cin >> a;
cout << fixed << setprecision(3) << sqrt(2.0) * a;
return 0;
}
```
**易错提醒:** 使用 `2.0` 可以明确进行浮点运算。
### 扩展2三个数的中间数【基础综合】
**题目描述:** 输入三个互不相同的整数,使用 `max``min` 输出大小居中的数。
**输入格式:** 三个整数。
**输出格式:** 中间数。
**数据范围:** 每个数的绝对值不超过 `10^9`
**输入样例:**
```text
9 2 6
```
**输出样例:**
```text
6
```
**解题思路:** 三数之和减去最大值和最小值。
**参考代码:**
```cpp
#include <iostream>
#include <algorithm>
using namespace std;
int main() {
long long a, b, c;
cin >> a >> b >> c;
long long biggest = max(a, max(b, c));
long long smallest = min(a, min(b, c));
cout << a + b + c - biggest - smallest;
return 0;
}
```
**易错提醒:** 三数之和可能超过 `int`,这里使用 `long long`
### 扩展3成绩极差【中等】
**题目描述:** 输入若干个成绩,输出最低分、最高分以及两者之差。
**输入格式:** 第一行输入成绩数量;第二行输入所有成绩。
**输出格式:** 依次输出最低分、最高分和极差。
**数据范围:** `1≤n≤100`,成绩为 `0100`
**输入样例:**
```text
4
80 60 90 70
```
**输出样例:**
```text
60 90 30
```
**解题思路:** 用第一个成绩初始化最值,随后逐一调用 `max``min` 更新。
**参考代码:**
```cpp
#include <iostream>
#include <algorithm>
using namespace std;
int main() {
int n, score, biggest, smallest;
cin >> n;
cin >> score;
biggest = smallest = score;
for (int i = 1; i < n; i++) {
cin >> score;
biggest = max(biggest, score);
smallest = min(smallest, score);
}
cout << smallest << " " << biggest << " " << biggest - smallest;
return 0;
}
```
**易错提醒:** 当只有一个成绩时,最低分和最高分相同,极差为 0。
### 扩展4口令规范化【中等】
**题目描述:** 输入一个不含空格的口令,把其中所有字母转成大写,数字和符号保持不变。
**输入格式:** 一个不含空格的字符串。
**输出格式:** 转换后的字符串。
**数据范围:** 字符串长度不超过 100。
**输入样例:**
```text
GesP2026!
```
**输出样例:**
```text
GESP2026!
```
**解题思路:** 逐个检查字符;是字母就调用 `toupper`
**参考代码:**
```cpp
#include <iostream>
#include <string>
#include <cctype>
using namespace std;
int main() {
string s;
cin >> s;
for (int i = 0; i < (int)s.size(); i++) {
if (isalpha(s[i])) s[i] = (char)toupper(s[i]);
}
cout << s;
return 0;
}
```
**易错提醒:** 不要改动数字和符号。
### 扩展5离目标最近的数【中等】
**题目描述:** 输入 `n` 个整数和目标值 `t`,输出与 `t` 的差的绝对值最小的数;若并列,输出较小者。
**输入格式:** 第一行输入整数数量和目标值;第二行输入所有整数。
**输出格式:** 满足条件的整数。
**数据范围:** `1≤n≤100`,输入整数绝对值不超过 10000。
**输入样例:**
```text
4 10
8 12 15 3
```
**输出样例:**
```text
8
```
**解题思路:** 用第一个数初始化答案;比较 `abs(x-t)`,相等时比较数值大小。
**参考代码:**
```cpp
#include <iostream>
#include <cmath>
using namespace std;
int main() {
int n, t, x, answer;
cin >> n >> t >> answer;
for (int i = 1; i < n; i++) {
cin >> x;
if (abs(x - t) < abs(answer - t) ||
(abs(x - t) == abs(answer - t) && x < answer)) {
answer = x;
}
}
cout << answer;
return 0;
}
```
**易错提醒:** 不能把答案初始化为 0因为 0 不一定在输入中。
### 扩展6最接近平均值的成绩【略难】
**题目描述:** 输入 `n` 个整数成绩,求平均值,并输出最接近平均值的成绩;若并列,输出较小者。
**输入格式:** 第一行输入成绩数量;第二行输入所有成绩。
**输出格式:** 一个成绩。
**数据范围:** `1≤n≤100`,成绩为 `0100`
**输入样例:**
```text
4
60 70 80 100
```
**输出样例:**
```text
80
```
**解题思路:** 先求浮点平均值,再使用 `abs` 进行二次打擂台。
**参考代码:**
```cpp
#include <iostream>
#include <cmath>
using namespace std;
int main() {
int n, a[105], sum = 0;
cin >> n;
for (int i = 0; i < n; i++) {
cin >> a[i];
sum += a[i];
}
double average = 1.0 * sum / n;
int answer = a[0];
for (int i = 1; i < n; i++) {
double now = abs(a[i] - average);
double best = abs(answer - average);
if (now < best || (now == best && a[i] < answer)) {
answer = a[i];
}
}
cout << answer;
return 0;
}
```
**易错提醒:** 平均值必须使用浮点除法;并列规则不能遗漏。
### 扩展7统一大小写并分类统计【略难】
**题目描述:** 输入一个不含空格的字符串,把所有字母转成小写,并统计原字符串中大写字母、小写字母和数字的数量。
**输入格式:** 输入一个不含空格的字符串。
**输出格式:** 第一行输出转换后的字符串;第二行依次输出三类字符数量。
**数据范围:** 字符串长度为 1100。
**输入样例:**
```text
AbC2026xY
```
**输出样例:**
```text
abc2026xy
3 3 4
```
**解题思路:** 遍历原字符串,先分类计数,再对字母调用 `tolower`
**参考代码:**
```cpp
#include <iostream>
#include <cctype>
#include <string>
using namespace std;
int main() {
string s;
int upper = 0, lower = 0, digit = 0;
cin >> s;
for (char &c : s) {
if (isupper(c)) upper++;
else if (islower(c)) lower++;
else if (isdigit(c)) digit++;
if (isalpha(c)) c = (char)tolower(c);
}
cout << s << "\n";
cout << upper << " " << lower << " " << digit;
return 0;
}
```
**易错提醒:** 分类统计必须依据转换前的字符;数字不参与大小写转换。