编程是数学的抽象
A
B
最近有一位家长在群里贴了一道数学题,是这样的:
甲一分钟能洗3个盘子或9个碗,乙一分钟能洗2个盘子或7个碗,甲、乙合作,20分钟洗了134个盘子和碗,问有几个盘子几个碗?
这位家长觉得这个题目可以通过编程来求解。
首先要说明的是,这位家长很厉害,原来不懂编程,但跟在孩子后面听了一段时间,现在已经懂很多了,虽然不一定能写出代码,但那种编程的感觉和思维已经有了。
我正在写 GESP 二级教程,正愁找不到枚举类型的题目,于是把它变成了一道编程题:
小格一分钟能洗 a 个盘子或 b 个碗,小蠹一分钟能洗 c 个盘子或 d 个碗。现在小格和小蠹一起,m 分钟洗了 n 个盘子和碗,那么他们洗了几个盘子和几个碗?输入一行 6 个正整数,分别表示 a、b、c、d、m、n,所有数字都不超过 10000。输出一行,两个数字,如果有多种可能,只要输出一种就可以;如果答案不存在,就输出 error。
这是个妥妥的枚举类型的题目,只要假设小格 i 分钟洗盘子,(m-i) 分钟洗碗,0<=i<=m,小蠹j分钟洗盘子,(m-j) 分钟洗碗,0<=j<=m,那么组合(i,j)(0<=i<=m,0<=j<=m)就是所有可能的方案,条件就是 a*i + (m-i)*b + c*j + (m-j)*d == n。所以,使用两层循环,对 i 和 j 枚举就行。代码如下:
#include <iostream>
using namespace std;
int main(){
int a, b, c, d, m, n;
bool has = false;
cin >> a >> b >> c >> d >> m >> n;
for(int i=0; i<=m; i++){
for(int j=0; j<=m; j++){
if(a*i + b*(m-i) + c*j + d*(m-j) == n){
has = true;
cout << a*i + c*j << ' ' << b*(m-i) + d*(m-j) << endl;
break;
}
}
}
if(!has)
cout << "error" << endl;
return 0;
}
然后运行输入 3 9 2 7 20 134,输出 84 和 50,所以他们洗了 84 个盘子、50 个碗。
当然,这毕竟是一道数学题,所以我同时也给出了数学里的解题方法。
设甲用 i 分钟洗盘子,(20-i) 分钟洗碗,乙用 j 分钟洗盘子,(20-j) 分钟洗碗,那么:
3i + 9×(20-i) + 2j + 7×(20-j) = 134
变换得到:
6i + 5j = 186
这是一个二元一次方程,我们需要对 i 或者 j 从 0 到 20 一个一个去试。
我们把这个式子稍微变换一下:
5(i+j) = 186-i
要让 (186-i) 是 5 的倍数,i 只能取 1、6、11、16 四个数字,这样就减少了范围。通过计算发现,只有i等于 16 时,j 的值是合理的。最后再分别计算出盘子和碗的数量。
问题到这里还没有结束。现在假设我们把题目里的数字变一下,比如变成:
甲一分钟能洗 8 个盘子或 7 个碗,乙一分钟能洗 9个盘子或 3 个碗,甲、乙合作,15 分钟洗了 151 个盘子和碗,有几个盘子几个碗?
那么现在解题思路还是一样的,但是数字变了,最后得到的方程也不一样,需要重新求解,所以等于变成另外一道题目了。
但是如果把它转变成编程题,还是一样的,代码没有任何变化。
不但如此,如果我们把人物变一变,把洗的东西也变一变,甚至不是洗东西,而是摘水果、捉鱼虾,甚至不是说一分钟能做几个什么,而是完全变成不同的场景,比如变成这样:
张三能用一套乐高积木搭出7辆小汽车或者 5 辆坦克,李四能用一套乐高积木搭出 8 辆小汽车或者 4 辆坦克,现在他们分别用 5 套乐高积木搭了 73 辆小汽车和坦克,问其中有几辆小汽车几辆坦克?
这个题目如果转成编程题,代码还是一样的,不需要任何变化。
这说明了什么?这就说明了,编程是数学的高度抽象。一道编程题可以对应于好几道不同的数学题,一道数学题是一个具体的实例,而一道编程题是一个统一的实现。怎么做到的?通过抽象和变量来实现。你首先要会解原来的数学题,然后从具体的数字抽象出数据之间的关系,一旦关系找出来了,就与具体的场景无关了,这样这份代码就能适用不同的场景。所以编程需要很高的抽象能力,同时数学是编程的基础,从 a 抽象到 b,如果没有 a 或者没有抽象能力,那就得不到 b。
为什么数据变了,代码不用改变?因为编程并不是直接对数字计算,而是对变量计算,所有的加减乘除余和条件判断,都是对变量进行的,运行时对变量输入了不同的值,就会得到不同的结果。对变量计算,要比直接对数字计算复杂得多,所以编程需要很高的想象能力,把变量想象成一个具体的数字。如果没有想象能力,看到一堆变量就头皮发麻,是编不了程序的。
那么反过来,学习编程对数学有用吗?当然有用。前面说了从 a 抽象到 b,如果没有 a 或者没有抽象能力,那就得不到 b。但是如果别人把 b 告诉你了,你从 b 具象到 a,那太容易了。具象要比抽象简单。学习编程,并不是每道题目都能自己解出来,但是通过学习别人的代码,也能让自己进步。自己的编程能力提高了,就会反馈到数学里,数学成绩也会提高。
通过这个例子,还可以看出一个问题,就是出一道编程题要比出一道数学题难多了。前面举了那么多不同的例子,但是到了编程题里,代码都是一样的(编程题是不是一样,不是看题面的描述,而是看代码,只要代码是一样的,就可以看成是一样的题目)。所以,如果你能出一道编程题,那说明你很厉害了。
-END-
【盛格塾】
正心诚意,格物致知
以人文情怀审视软件,以软件技术改变人生
格友公众号
盛格塾小程序
扫描上方二维码或在微信中搜索“盛格塾”小程序
可以阅读更多文章和有声读物
往期推荐