
四级考试,不要再追求"学更多算法",而应该把已经学过的东西练到"题目一变,代码还能写出来"。
明天编程题最值得巩固的就是:
结构体 + 排序 + 手写
cmp再配合:
暴力枚举 + 模拟 + 贪心 +
sort()。
一、首先给孩子吃一颗定心丸
四级的核心其实是把基础算法组合起来。
同学们明天真正需要做到的是:
读懂题目
↓
把数据装进数组/结构体
↓
排序 / 枚举 / 模拟
↓
按照题目要求判断
↓
输出
今晚要做的是:
把最可能拿分的 50 分编程题,尽量变成"熟题"。
二、第一重点:结构体 + sort() + 手写 cmp
如果只能让大家,今晚练一道模板,我会选择这个。
最基础结构体
struct Student
{
int id;
int score;
};
例如:
Student a[1000];
三、sort() 的万能写法
按分数从高到低
bool cmp(Student a, Student b)
{
return a.score > b.score;
}
然后:
sort(a, a + n, cmp);
这三句话必须熟。
四、如果有两个排序条件怎么办?
这是我认为明天非常值得防的一种变化。
例如:
按成绩从高到低;
如果成绩相同,编号从小到大。
那么:
bool cmp(Student a, Student b)
{
if (a.score != b.score)
return a.score > b.score;
return a.id < b.id;
}
孩子一定要理解:
第一关键字不同
↓
比较第一关键字
第一关键字相同
↓
比较第二关键字
五、如果有三个排序条件呢?
继续往下写:
bool cmp(Student a, Student b)
{
if (a.score != b.score)
return a.score > b.score;
if (a.age != b.age)
return a.age < b.age;
return a.id < b.id;
}
所以送给孩子一句话:
排序不是难在
sort(),而是难在"想清楚谁应该排在谁前面"。
六、特别提醒:cmp 里面千万不要写反
这是四级最容易丢分的地方之一。
题目:
从大到小。
写:
return a.score > b.score;
题目:
从小到大。
写:
return a.score < b.score;
记忆方法:
左边应该排在右边前面,就返回
true。
七、6月份《身高体重指数》就是非常好的训练题
6 月第二道编程题要求按照 BMI 从高到低排序,并输出排序后的编号。
当时官方程序定义:
struct Human
{
int id;
int w;
double h;
};
然后计算:
double bmi1 =
(double)humans[j-1].w
/ humans[j-1].h
/ humans[j-1].h;
再根据 BMI 从高到低交换。
这道题如果放到今天的课堂里,我会要求孩子不要只会抄官方冒泡排序。
而是要求他能够改写成:
bool cmp(Human a, Human b)
{
double bmi1 = (double)a.w / a.h / a.h;
double bmi2 = (double)b.w / b.h / b.h;
return bmi1 > bmi2;
}
然后:
sort(humans, humans + n, cmp);
这才是真正的四级能力。
八、今晚第二重点:暴力枚举
四级非常重要的思想:
范围不大,就一个一个试。
例如:
for (int i = 1; i <= n; i++)
{
// 检查 i
}
两个东西:
for (int i = 0; i < n; i++)
{
for (int j = i + 1; j < n; j++)
{
// 检查 a[i] 和 a[j]
}
}
孩子看到:
"任选两个......"
第一反应就应该是:
for (i)
for (j)
看到:
"任选三个......"
就想到:
for (i)
for (j)
for (k)
当然,要先判断数据范围是否允许。
九、第三重点:模拟
模拟题最可怕的不是算法,而是:
题目看懂了,代码写错了。
6 月第一道编程题《扫雷》就是非常典型的模拟。
题目要求给出雷区位置,然后计算每个非雷区周围有多少个雷。并且"相邻"的定义是有公共顶点即可,所以一个内部格子最多检查周围 8 个格子。
官方程序采用:
for (int di = -1; di <= 1; ++di)
{
for (int dj = -1; dj <= 1; ++dj)
{
...
}
}
来检查周围 3×3 范围。
这类题明天仍然可能换皮:
棋盘
地图
机器人
灯泡
座位
游戏地图
统计邻居
故事完全可以变。
但是本质可能还是:
按照题目的规则,一步一步模拟。
十、模拟题一定反复检查"边界"
比如:
if (i + di < 0 || i + di >= n ||
j + dj < 0 || j + dj >= m)
continue;
这类代码非常重要。
因为小学生做模拟题,最常见的错误不是不会算法,而是:
数组越界
行列写反
i/j 写反
< 写成 <=
坐标从 1 开始却按 0 开始处理
所以我建议明天考场上:
凡是涉及二维数组,第一件事就是确认坐标从 0 还是 1 开始。
6 月的《扫雷》特别强调了行号和列号的编号范围。
十一、第四重点:贪心
四级如果出现贪心,我反而不建议孩子想得太复杂。
先问:
"每一步,我应该选择什么?"
例如:
尽可能多
尽可能少
最大
最小
优先选择......
很可能需要:
sort();
然后按照某种顺序依次选择。
所以:
四级贪心经常和排序是一对好朋友。
例如:
sort(a, a + n);
然后:
for (int i = 0; i < n; i++)
{
if (满足条件)
{
// 选择
}
}
十二、所以我认为明天最重要的"算法地图"是这个
GESP 4级编程题
│
┌────────────┼────────────┐
↓ ↓ ↓
排序 枚举 模拟
│ │ │
sort+cmp for 按规则
│ │ │
└────────────┼────────────┘
↓
贪心
│
sort后选择
这几个东西不是互相独立的。
很可能一道题是:
结构体 + sort + cmp + 贪心
另一道题是:
二维数组 + 模拟 + 枚举
也可能两道题都是:
结构体 + sort + cmp
这正是你所说的:
"两道题都有可能用到 sort。"
十三、我特别建议今晚把 cmp 练到"条件反射"
要看到:
从小到大
bool cmp(int a, int b)
{
return a < b;
}
从大到小
bool cmp(int a, int b)
{
return a > b;
}
结构体单关键字
bool cmp(Student a, Student b)
{
return a.score > b.score;
}
结构体双关键字
bool cmp(Student a, Student b)
{
if (a.score != b.score)
return a.score > b.score;
return a.id < b.id;
}
三关键字
bool cmp(Student a, Student b)
{
if (a.score != b.score)
return a.score > b.score;
if (a.age != b.age)
return a.age < b.age;
return a.id < b.id;
}
这几种今晚至少自己敲一遍。
十四、还要特别防一个坑:cmp 不是"比较两个元素谁更大"
这是很多同学的误区。
比如:
bool cmp(Student a, Student b)
{
return a.score > b.score;
}
它表达的不是:
"a 比 b 大。"
而是:
"如果 a 应该排在 b 前面,返回 true。"
这一点一旦理解,复杂排序就容易很多。
十五、明天考场上,拿到编程题先不要急着敲代码
我建议四级考试,同学们要形成一个固定流程:
第一步:圈关键词
看到:
最大
最小
排序
第K
前K
从大到小
从小到大
如果相同
最多
最少
选择
马上警觉。
第二步:确定数据结构
如果每个人有:
编号
成绩
年龄
身高
体重
不要搞一堆数组。
直接:
struct Student
{
int id;
int score;
int age;
};
第三步:判断是否需要排序
如果题目出现:
按......排序
直接想到:
sort();
然后写:
cmp
第四步:判断算法
今晚只需要优先问:
是不是直接枚举?
是不是模拟?
是不是排序后贪心?
十六、明天不要在一道题上死磕
这是最后我特别想提醒四级孩子的。
25 分的编程题:
如果你已经:
看懂输入
看懂输出
变量定义完成
基本代码完成
但是某个细节卡住了......
先保存、提交、继续下一题。
不要因为一个 25 分题,把另外 25 分也搭进去。
十七、最后一晚,我建议这样安排
现在距离考试只有一天了,我会安排:
第一轮:20分钟
默写:
struct
sort
cmp
重点练:
单条件、双条件、三条件排序。
第二轮:20分钟
重新做 6 月《身高体重指数》。
目标不是重新做出答案,而是:
不用看参考程序,自己用
struct + sort + cmp写一遍。
第三轮:20分钟
重新看 《扫雷》。
重点不是背代码,而是检查:
二维数组
行列
边界
8个方向
模拟
第四轮:20分钟
练一道:
结构体 + 双关键字排序 + 贪心
以及一道:
枚举 / 模拟
最后 10 分钟
只看自己的"易错清单"。
不要再学新东西。
十八、给四级学生的"明日必背 10 句话"
①编程题, 看到排序,先想
sort()。②
sort()不会排序,问题通常出在cmp。③
cmp返回 true,表示左边应该排在右边前面。④ 从小到大
<,从大到小>。⑤ 两个排序条件,第一个相同再比较第二个。
⑥ 看到"任选两个",首先考虑两重循环。
⑦ 看到地图、棋盘、游戏规则,首先想模拟。
⑧ 贪心题先排序,再想每一步选什么。
⑨ 二维数组题,先确认行列和下标范围。
⑩ 不要因为题目的故事复杂,就以为算法复杂。
最后给大家的一句话
明天不是去证明"我会多少算法",而是去把我已经会的东西,一个一个拿回来。
结构体会不会?
sort()会不会?
cmp会不会?循环会不会?
模拟会不会?
枚举会不会?
贪心会不会?
把这些基本功做好,四级的编程题就已经有了非常坚实的得分基础。
题目可以换皮,代码骨架不会轻易变。