这是一份针对北师大版小学数学四年级(上册 + 下学期)教学大纲设计的完整版“数学 + 信奥(C++ 编程)”衔接培训讲义。讲义通过 6 个核心专题,将四年级的数学数感、几何、代数、行程及统计知识,与 C++ 基础算法(拆数、枚举、分支、循环、模拟)无缝融合。
目录
- 第一讲:认识更大的数 —— 亿级大数的数位剥离与数位特征判定
- 第二讲:速度、时间与路程 —— 追及与相遇问题的计算机模拟
- 第三讲:运算律与巧算 —— 高斯求和与算法效率的初步感知
- 第四讲:三角形的三边关系 —— 逻辑分支与几何分类判定
- 第五讲:方程与等量关系 —— 经典“鸡兔同笼”的枚举算法实现
- 第六讲:平均数与数据分析 —— 统计中的最值搜索与均值计算
第一讲:认识更大的数 —— 亿级大数的数位剥离与数位特征判定
【学习目标】
- 数学目标:巩固万级、亿级数的数位顺序表,理解数位与计数单位的关系。
- 编程目标:掌握 C++ 中除法(
/)与取模(%)的数位剥离技巧,掌握while循环的基本用法。
【数学核心要点】
在北师大版四上第一单元中,我们认识了更大的数(十万、百万、千万、亿等)。一个大数是由各个数位上的数字组成的。例如:在数位顺序表中,十万位上的 $5$ 表示 $5$ 个十万。
在奥数中,我们经常遇到数位特征问题,例如:“一个多位数,它的个位和百位相同……”或“求一个数各位数字的和”。
【信奥核心要点】
在 C++ 编程中,处理一个大数的数位,我们不需要把它当成字符串,而是利用纯数学运算:
1. 取最后一位(个位):num % 10。
2. 去掉最后一位:num / 10。
通过一个条件为 num > 0 的 while 循环,我们可以依次剥离出任意大数的每一位。
【经典奥数例题】
例题:小明在纸上写了一个五位数,这个五位数从左往右读和从右往左读是一样的(这种数称为回文数)。已知这个数万位上的数字是 $8$,且所有数位上的数字之和是 $24$。请问这个五位数的百位数字是多少?
数学解析: 1. 因为是五位数且回文,设这个五位数为 $\overline{abcba}$。 2. 万位是 $8$,所以 $a = 8$。因此,个位也是 $8$。 3. 目前已知:$8 + b + c + b + 8 = 24$,简化得 $2b + c = 8$。 4. 根据回文数定义,数位上的数均为 $0 \sim 9$ 的整数。 5. 若我们要用 C++ 验证或找出所有满足条件的五位回文数,我们可以写一个通用的数位判定程序。
【C++ 算法实现】
输入任意一个五位数,判断它是否为回文数,并输出其各位数字之和。
#include <iostream>
using namespace std;
int main() {
int num;
cout << "请输入一个五位数:";
cin >> num;
// 检查输入范围是否为五位数
if (num < 10000 || num > 99999) {
cout << "输入错误,必须是五位数!" << endl;
return 0;
}
int temp = num;
int original_num = num;
// 剥离各个数位
int units = temp % 10; // 个位
temp /= 10;
int tens = temp % 10; // 十位
temp /= 10;
int hundreds = temp % 10; // 百位
temp /= 10;
int thousands = temp % 10; // 千位
temp /= 10;
int ten_thousands = temp; // 万位
// 计算各位数字之和
int sum = units + tens + hundreds + thousands + ten_thousands;
cout << "万位:" << ten_thousands << ",千位:" << thousands
<< ",百位:" << hundreds << ",十位:" << tens << ",个位:" << units << endl;
cout << "数位之和为:" << sum << endl;
// 判断是否为回文数 (万位==个位 且 千位==十位)
if (ten_thousands == units && thousands == tens) {
cout << original_num << " 是一个回文数!" << endl;
} else {
cout << original_num << " 不是回文数。" << endl;
}
return 0;
}
【课后练习】
- 数位累乘:编写程序,输入一个四位数,计算并输出它各个数位上非零数字的乘积。
- 大数重组:输入一个三位数,将其百位与个位对换,输出新组成的三位数(例如输入
123,输出321)。
第二讲:速度、时间与路程 —— 追及与相遇问题的计算机模拟
【学习目标】
- 数学目标:牢固掌握关系式 $\text{路程} = \text{速度} \times \text{时间}$,理解相遇问题与追及问题的本质。
- 编程目标:学习使用变量和循环(
while或for)来模拟物理/时间变化过程。
【数学核心要点】
北师大版四上第六单元引入了《除法》中的核心应用:路程、时间与速度。 * 相遇问题:$\text{相遇时间} = \text{总路程} \div \text{速度和}$ * 追及问题:$\text{追及时间} = \text{路程差} \div \text{速度差}$
【信奥核心要点】
在计算机科学中,除了用公式直接计算外,我们常用“时标模拟法”(Simulation)。即:让时间每过去 $1$ 秒,更新两者的位置坐标,直到它们相遇或追上。这种模拟思想是编写游戏、物理引擎及复杂信奥题目的基础。
【经典奥数例题】
例题:甲、乙两人相距 $100$ 米。甲在后,速度为每秒 $5$ 米;乙在前,速度为每秒 $3$ 米。两人同时同向出发,请问甲多少秒后可以追上乙?
数学解析: 1. 路程差 = $100$ 米,速度差 = $5 - 3 = 2$ 米/秒。 2. 追及时间 = $100 \div 2 = 50$ 秒。
【C++ 算法实现】
我们使用计算机模拟这个过程,每秒更新一次两者的位置。
#include <iostream>
using namespace std;
int main() {
int pos_A = 0; // 甲的初始位置在原点 0
int pos_B = 100; // 乙的初始位置在 100 米处
int speed_A = 5; // 甲的速度
int speed_B = 3; // 乙的速度
int second = 0; // 计时器
// 只要甲还没追上乙,就继续跑
while (pos_A < pos_B) {
second++; // 时间流逝 1 秒
pos_A += speed_A; // 甲前行
pos_B += speed_B; // 乙前行
// 打印每秒的动态(可用于观察程序运行过程)
// cout << "第 " << second << " 秒: 甲在 " << pos_A << "米, 乙在 " << pos_B << "米" << endl;
}
cout << "甲在第 " << second << " 秒追上了乙!" << endl;
cout << "相遇时的位置是距离起点 " << pos_A << " 米。" << endl;
return 0;
}
【课后练习】
- 反向相遇:甲乙两人相距 $300$ 米,甲的速度是 $4$ 米/秒,乙的速度是 $6$ 米/秒,两人同时相向而行。编写程序模拟并计算他们相遇所需的时间。
- 环形跑道:甲、乙两人在环形跑道上跑步,跑道一周长 $400$ 米。甲速度 $6$ 米/秒,乙速度 $4$ 米/秒。两人在同一地点同时同向出发,编写程序计算甲第一次超越乙(即比乙多跑一整圈)需要多少秒。
第三讲:运算律与巧算 —— 高斯求和与算法效率的初步感知
【学习目标】
- 数学目标:掌握等差数列求和的原理(高斯求和公式)。
- 编程目标:对比“循环累加”与“公式计算”,初步建立算法时间复杂度的概念。
【数学核心要点】
在四上第四单元中,我们学习了《运算律》。简便运算的精髓在于寻找规律并化繁为简。 经典奥数题目中,等差数列求和(高斯求和)是最具代表性的速算: $$\text{和} = (\text{首项} + \text{末项}) \times \text{项数} \div 2$$
【信奥核心要点】
在编程中,求 $1$ 到 $N$ 的累加和,我们有两种写程序的方法:
* 方法 A:用 for 循环从 $1$ 累加到 $N$。如果 $N = 10^9$,计算机需要执行十亿次加法,耗时明显。
* 方法 B:直接套用高斯公式 (1 + N) * N / 2。无论 $N$ 多大,计算机只需做一次加法、一次乘法和一次除法,瞬间完成。
这让我们认识到:优秀的算法可以极大地减少计算步骤。
【经典奥数例题】
例题:求自然数 $1$ 到 $100$ 的所有数之和。
数学解析: $\text{和} = (1 + 100) \times 100 \div 2 = 101 \times 50 = 5050$。
【C++ 算法实现】
我们编写两套算法来解决求和问题,感受公式的威力。
#include <iostream>
using namespace std;
int main() {
long long N;
cout << "请输入最大正整数 N:";
cin >> N;
// --- 方法 A:循环累加(模拟法) ---
long long sum_loop = 0;
for (long long i = 1; i <= N; ++i) {
sum_loop += i;
}
cout << "【方法 A】通过循环计算,和为:" << sum_loop << endl;
// --- 方法 B:公式巧算(高斯求和) ---
long long sum_formula = (1 + N) * N / 2;
cout << "【方法 B】通过公式巧算,和为:" << sum_formula << endl;
return 0;
}
注:当输入 $N = 100000000$(一亿)时,你会发现方法 B 瞬间出结果,而方法 A 会有轻微的停顿。这就是算法效率的区别。
【课后练习】
- 奇数之和:编写程序,求 $1$ 到 $100$ 之间所有奇数的和(即 $1 + 3 + 5 + \dots + 99$),尝试用循环和等差数列公式两种方式实现。
- 阶梯储蓄法:小明第一天存 $1$ 元,第二天存 $2$ 元,第三天存 $3$ 元……依此类推。编写程序输入天数 $D$,输出小明一共存了多少钱。
第四讲:三角形的三边关系 —— 逻辑分支与几何分类判定
【学习目标】
- 数学目标:理解三角形三边长度的约束关系,掌握等腰、等边三角形的几何性质。
- 编程目标:熟练掌握 C++ 多分支结构(
if-else if-else)及逻辑运算符&&(并且)、||(或者)。
【数学核心要点】
在四下第二单元中,我们认识了三角形。 1. 三边性质:任意两边之和大于第三边。即已知三边为 $a, b, c$,必须满足: $$a+b>c \quad \text{且} \quad a+c>b \quad \text{且} \quad b+c>a$$ 2. 三角形分类: * 等边三角形:三边相等。 * 等腰三角形:有两边相等。 * 普通三角形:三边互不相等。
【信奥核心要点】
这是一个典型的多层条件嵌套问题。在编程中,我们要先判断“能否构成三角形”,在确保能构成的前提下,再进入内部的分支去细分它的种类。逻辑运算符的使用必须要严谨。
【经典奥数例题】
例题:有三根小棒,长度分别为 $5\text{cm}$,$5\text{cm}$,$12\text{cm}$。它们能围成一个三角形吗?如果不能,请说明理由。如果要围成一个等腰三角形,第三根小棒最少要整厘米数多少?
数学解析: 1. 因为 $5 + 5 = 10 < 12$,两边之和小于第三边,所以不能围成三角形。 2. 若要围成等腰三角形,且已知两边是 $5$ 和 $12$。第三边只能是 $5$ 或 $12$。 * 如果第三边是 $5$,则三边为 $5, 5, 12$(不能构成)。 * 如果第三边是 $12$,则三边为 $5, 12, 12$。因为 $5+12>12$,所以可以构成等腰三角形。
【C++ 算法实现】
#include <iostream>
using namespace std;
int main() {
int a, b, c;
cout << "请输入三角形的三条边长 a, b, c(用空格隔开):";
cin >> a >> b >> c;
// 1. 验证三边关系定理
if (a + b > c && a + c > b && b + c > a) {
cout << "这三条边可以构成三角形!" << endl;
// 2. 嵌套分支:判定具体类型
if (a == b && b == c) {
cout << "它是一个【等边三角形】。" << endl;
}
else if (a == b || b == c || a == c) {
cout << "它是一个【等腰三角形】。" << endl;
}
else {
cout << "它是一个【普通三角形】。" << endl;
}
}
else {
cout << "这三条边无法构成三角形!因为不满足任意两边之和大于第三边。" << endl;
}
return 0;
}
【课后练习】
- 直角三角形判定:修改上面的程序,增加一个判定条件:如果三边满足 $a^2 + b^2 = c^2$(假设 $c$ 是最大边),则输出“它还是一个直角三角形”。
- 三角形周长:输入三个整数,如果能构成三角形,输出该三角形的周长;如果不能,输出
0。
第五讲:方程与等量关系 —— 经典“鸡兔同笼”的枚举算法实现
【学习目标】
- 数学目标:巩固代数方程思想,体会设未知数建立等量关系的解题思路。
- 编程目标:理解“穷举法”(暴力搜索)在计算机中的应用,掌握循环结构解决实际代数问题的技巧。
【数学核心要点】
在四下第五单元中,我们学习了《认识方程》。 对于经典的奥数“鸡兔同笼”问题: * 设鸡有 $x$ 只,兔有 $y$ 只。 * 已知总头数 $H$,总脚数 $F$。 * 方程组为: $$\begin{cases} x + y = H \ 2x + 4y = F \end{cases}$$
【信奥核心要点】
虽然代数消元法能一步求出答案,但在信息学中,面对条件更复杂、未知数更多的方程(如“百钱买百鸡”),枚举算法(Exhaustive Search) 更加直观和强大。 我们利用循环,让鸡的数量从 $0$ 变到 $H$,对每一种情况计算兔子的数量,并判断脚数是否正确。
【经典奥数例题】
例题:鸡和兔共 $35$ 个头,$94$ 只脚。求鸡和兔各有多少只?
数学解析(方程法): 设鸡有 $x$ 只,则兔有 $35 - x$ 只。 $$2x + 4(35 - x) = 94$$ $$2x + 140 - 4x = 94 \implies 2x = 46 \implies x = 23$$ 兔有 $35 - 23 = 12$ 只。
【C++ 算法实现】
我们用循环模拟计算机“一个一个去试”的求解逻辑。
#include <iostream>
using namespace std;
int main() {
int heads, feet;
cout << "请输入总头数:";
cin >> heads;
cout << "请输入总脚数:";
cin >> feet;
bool found = false;
// 枚举鸡的数量,范围在 0 到总头数之间
for (int chicken = 0; chicken <= heads; ++chicken) {
int rabbit = heads - chicken; // 剩下的就是兔子
// 验证脚数是否吻合
if (chicken * 2 + rabbit * 4 == feet) {
cout << "找到可行解!鸡有 " << chicken << " 只,兔有 " << rabbit << " 只。" << endl;
found = true;
break; // 找到一组正确解,结束搜索
}
}
if (!found) {
cout << "根据输入的数据,无法找到合理的鸡兔数量(无解)。" << endl;
}
return 0;
}
【课后练习】
- 三合一问题:如果笼子里除了鸡和兔子,还加入了一只脚都没有的蛇。已知头共 $10$ 个,脚共 $20$ 只。编写程序,输出所有可能的动物组合情况(鸡、兔、蛇各多少只)。
- 百钱买百鸡:公鸡 $5$ 文钱一只,母鸡 $3$ 文钱一只,小鸡 $3$ 只共 $1$ 文钱。用 $100$ 文钱买 $100$ 只鸡,编写程序输出所有可能的购买方案。
第六讲:平均数与数据分析 —— 统计中的最值搜索与均值计算
【学习目标】
- 数学目标:理解平均数的概念,掌握计算一组数据平均数的方法。
- 编程目标:掌握在循环输入中寻找最大值(Max)和最小值(Min)的基本算法。
【数学核心要点】
在四下第六单元中,我们学习了《数据的表示和分析》。 * 平均数:一组数据的总和除以这组数据的个数。平均数反映了一组数据的集中趋势。 $$\text{平均数} = \text{总数} \div \text{份数}$$ * 在实际统计中,为了客观评估,经常需要去掉一个最高分和一个最低分,再求平均数。
【信奥核心要点】
在计算机编程中,寻找“最值”是一个非常经典的算法。其核心思想是:“打擂台法”。 1. 设定一个极小的初始值作为最大值的擂主,或设定一个极大的初始值作为最小值的擂主。 2. 每输入一个新的数据,就和擂主比武。如果它比擂主大(或小),它就成为新的擂主。
【经典奥数例题】
例题:某次数学竞赛中,小组成员的成绩分别为:$90, 95, 82, 100, 88$ 分。求这组数据的平均成绩。
数学解析: 1. 总分 = $90 + 95 + 82 + 100 + 88 = 455$ 分。 2. 人数 = $5$ 人。 3. 平均分 = $455 \div 5 = 91$ 分。
【C++ 算法实现】
本程序不仅计算平均数,还能在输入数据的过程中,自动找出这组数据中的最高分与最低分。
#include <iostream>
using namespace std;
int main() {
int n;
cout << "请输入学生人数:";
cin >> n;
if (n <= 0) {
cout << "人数必须大于 0!" << endl;
return 0;
}
double sum = 0;
int max_score = -1; // 初始化最大值为一个极小的数
int min_score = 101; // 初始化最小值为一个极大的数(假设满分100)
for (int i = 1; i <= n; ++i) {
int score;
cout << "请输入第 " << i << " 个学生的成绩:";
cin >> score;
sum += score; // 累加总分
// 更新最高分(打擂台)
if (score > max_score) {
max_score = score;
}
// 更新最低分(打擂台)
if (score < min_score) {
min_score = score;
}
}
double average = sum / n;
cout << "---- 统计结果 ----" << endl;
cout << "最高分:" << max_score << " 分" << endl;
cout << "最低分:" << min_score << " 分" << endl;
cout << "平均分:" << average << " 分" << endl;
return 0;
}
【课后练习】
- 歌唱比赛评委打分:编写程序,输入 $5$ 位评委的打分,去掉一个最高分和一个最低分,输出该选手的最终平均得分(提示:用总分减去最高分和最低分,再除以 $3$)。
- 温度平均值:收集一周 7 天的日平均气温,找出本周的最热温度、最冷温度,以及这一周的平均气温。
附录:课后作业参考答案(部分思路提示)
第一讲练习 1(数位累乘)提示
// 核心逻辑
int temp = num, product = 1;
while(temp > 0) {
int d = temp % 10;
if(d != 0) {
product *= d;
}
temp /= 10;
}
第四讲练习 1(直角三角形判定)提示
// 寻找最大边并利用勾股定理判断
int max_side = a;
if (b > max_side) max_side = b;
if (c > max_side) max_side = c;
if (max_side == a) {
if (b*b + c*c == a*a) cout << "是直角三角形";
} else if (max_side == b) {
if (a*a + c*c == b*b) cout << "是直角三角形";
} else {
if (a*a + b*b == c*c) cout << "是直角三角形";
}
第五讲练习 2(百钱买百鸡)提示
// 双重循环枚举公鸡和母鸡,小鸡数量可以用 100 - x - y 算出来
for(int x = 0; x <= 20; ++x) { // 公鸡最多买20只
for(int y = 0; y <= 33; ++y) { // 母鸡最多买33只
int z = 100 - x - y; // 小鸡只数
if(z % 3 == 0 && 5*x + 3*y + z/3 == 100) {
cout << "公鸡:" << x << " 母鸡:" << y << " 小鸡:" << z << endl;
}
}
}
—— 本文来自火龙信奥(义乌睿码科技):义乌青少年信息学奥赛与编程教育平台,专注 CSP-J/S、NOIP、GESP 竞赛培训,线上线下融合教学,助力编程升学。网址:hlcoding.com