1
初二期末考试结束后的那个周末,陈远家的小饭桌上一如既往的温馨。
一盘掐了头尾、炒得清脆碧绿的青椒土豆丝,一碗炖得软烂入味的红烧肉。妈妈林华坐在桌子对面,正笑眯眯地给陈远夹了一块带软骨的排骨。作为市里一家大型国企的资深会计师,林华性格向来温柔大方,说话慢条斯理,笑起来的时候眼睛弯弯的,让人感觉特别踏实。
那张期末成绩单就放在旁边的五斗橱上,陈远这次发挥挺稳,依旧保持在年级前列,唯独数学最后一题因为漏掉了分类讨论的两种极端边界情况,被扣了六分。
“儿子,多吃点肉,这半个月看你吃学校食堂都瘦了。”林华端起茶杯喝了一口,语气里全是关心,顺便打趣道,“听你们班主任说,你这次数学最后一题漏了两个边界?这可不像你啊。不过妈妈作为会计,最能理解这种事。这就跟我们大考算账一样,中间的借贷方借平了不算赢,最后的‘轧账’边界稍微漏掉一个小数点,整张资产负债表就得重做。这次漏了是好事,说明咱账目查得还不够细,下次轧账的时候注意,争取把它平了!”
陈远咬着排骨,有些不好意思地笑了笑。他没法跟妈妈解释得太深。其实那道题他不是不会做,而是当时满脑子都在转着一道区间动态规划(区间DP)的竞赛题。在考场上,他的数理思维转得太快,以至于看纸面上的初中几何题时,下意识地把边界条件给“格式化”了。
“行了,别光顾着宽慰他。”
坐在主位上的陈知行放下了筷子,看了一眼儿子,挑了挑眉毛:“听说你小子最近在死磕一道NOIP的区间DP?吃完饭,把你的草稿本带上,跟我进书房,让老爸见识见识你最近又捣鼓出什么好玩的算法了。”
2
陈知行的书房里弥漫着一种陈旧书页与微机墨盒交织的独特气味。
靠墙的实木书架上,整整齐齐地码着当年他在哈工大计算机系时的专业课本,《微机原理》、《数字信号处理》,以及一叠数控厂的精密机床设计图纸。桌上那盏老式的日光台灯散发着柔和的光。
陈知行坐在藤椅上,把陈远那叠写满了密密麻麻状态转移方程的草稿纸平铺在桌面上。他戴上花镜,一页一页,极其仔细地审视着儿子手推的那些状态转移过程。
陈远有些兴奋地凑在旁边,嘴里还咬着一根冰棍,活泼地指着纸上的公式解释道:“爸,你看,这是经典的区间DP模型。大体上的状态转移方程我已经推出来了,但是这道题最恶心的地方在于,它在区间重叠和越界的极端边界下,数据会发生退化。我为了不让它跑出界,在状态转移方程外面专门套了四层特判逻辑,只要遇到 Corner Cases(极限情况)就强行拦截下来。我用家里电脑跑了几个测试样例,全过了!我是不是很聪明?”
陈知行看着儿子那一脸邀功的活泼样,嘴角微微扬了扬。他没有立刻夸奖,而是从抽屉里拿出一张崭新的制图白纸,和一把德国进口的精密钢直尺。
“小远,你过来。”父亲的声音很温和,却带着一种老一辈技术专家的严谨,“你的数理直觉很好,能想到处理极端边界,已经比绝大多数刚学编程的孩子强太多了。但是,你过来看看老爸画的这个。”
陈知行用铅笔在白纸上画了一个标准的闭环伺服电机控制轨迹。
“这是我们厂正在调试的数控车床主轴。在工业计算机控制里,我们要写‘插补算法’(Interpolation Algorithm)来控制刀具的切削轨迹。为了防止由于机械震动或者硬件过热产生的一微米零点漂移,我是不是应该在算法系统里写上一百个 if-else 条件,去强行纠正每一个位置的刀具误差?”
陈远愣了一下,吸了一口冰棍,挠挠头想了想:“那肯定不行啊。插补算法在单片机里是每毫秒都要迭代计算的,写那么多特判,程序执行周期就会变长,cpu根本算不过来,万一发生数据中断,机床当场就得撞刀崩溃。”
“太对了。”陈知行把铅笔放回桌上,发出一声清脆的钝响,赞许地看着儿子,“在工业级标准里,靠在核心算法外面堆砌特判去打补丁的系统,是最不稳定的。多一行逻辑分支,评测机在极限数据测试下就多了一分连环踩踏、当场爆零的风险。真正高级的插补算法,从来不需要补丁。”
3
陈知行站起身,走到书架前,把一本厚厚的、外皮已经有些磨损的《高级语言程序设计》抽了出来,稳稳地放在陈远面前。
大书落在桌面上,激起了一层微小的薄灰。
“信息学竞赛和我们搞微机控制是一样的,底层的本质全部是数学。你现在能推导出状态转移,说明你的数学底子已经打得挺像样了。但你老子当年在哈工大,听当年的老教授讲过一句话:‘算法的优雅,在于用数学的自洽去消灭边界,而不是用代码的臃肿去修补边界。’”
父亲伸出修长的手指,敲了敲那叠草稿纸。
“小远,你看看你写的这个区间重叠。你为什么要用特判呢?你如果把这个区间的几何映射,直接转化为一个二元代数方程,作为基准项融合进你的状态转移方程里,你觉得会怎么样?”
陈远整个人瞬间定格在了原地。
原本含在嘴里的冰棍都忘了嚼,那颗在奥数里浸泡了三年的脑子,在父亲这一句“用数学的自洽去消灭边界”的点拨下,瞬间拉出了一条无比清晰的逻辑通路!
他之前的特判,是因为他把数学方程和代码逻辑割裂开了,试图用代码去伺候数学。可事实上,代码只是数学的载体啊!只要在草稿纸上把代数模型的边界收束做得更完美,把极端情况直接化为方程里的常数项或者边界初始值——
“我明白了!”陈远兴奋得一拍大腿,“根本不需要那四层特判!只要在初始化递推矩阵的时候,把 dp[i][i 1] 的边界值用一个代数公因式统一赋值,三层循环套一个方程,直接就能把所有 Corner Cases 全部吞掉!”
看到儿子那恍然大悟、眼睛亮得像星光一样的兴奋模样,陈知行摘下花镜,露出了极其欣慰和骄傲的笑容。他重重地拍了拍儿子的肩膀:“哈哈,这才是老陈家的种!去吧,回房间用你的数学思维,把这段‘豆腐渣’代码给老子利落地重构了!”
“得咧!”
陈远一把抱起那本厚重的专业书和自己的草稿本,挺着胸脯、乐呵呵地跑回了自己的小房间。