数学实验室系列——物不知数续篇

上回书说到用枚举法解决物不知数问题,通过逐一检查9~1000的每一个自然数,得出了10个答案,它们分别是23、128、233等等(如附图所示),将这些答案填写在下面的表1中,来看一下它们之间的关系。

表1 十个答案之间的关系

表1中的第二行给出了两个相邻答案之间的差值,它们无一例外地都等于105,而105恰好等于3、5、7的乘积,也是它们的最小公倍数。这个结论是不是很有趣呢?它背后隐含着怎样的道理呢?

我们不得不说,23是一个了不起的数,它是全部答案的基石,在23的基础上,只要加上105的倍数,就可以得到无穷多个满足要求的答案。由于23满足除3余2、除5余3、除7余2的条件,而105又是3、5、7的最小公倍数,即,105能被3、5、7整除,因此105或105的倍数加上23所得的和,它们除以3、5、7所得的余数,与23除以3、5、7所得的余数相同。

有了这样的结论,我们的程序可以变得简单,而且运算次数大幅度减少。我们只需修改计算按钮点击事件中的程序,修改后的代码如图1所示。

图1 经过对答案的分析,改进了程序

这段程序几乎不需要计算机做任何数学运算(除了循环变量以105的幅度递增),它的主要任务是将答案拼接起来,并显示在标签中。我们将这种无需运算直接输出结果的求解方法命名为直取法。

我们可以做一个实验,比较两段程序的运行时间。在项目中添加一个计时器组件,在运算开始及结束时,分别记录下时间点,两个时间点的差就是运算耗费的时间。

在设计视图中添加计时器组件(在组件面板的传感器分组中),并取消勾选“一直计时”与“启用计时”属性,如图2所示。

图2 在设计视图中添加计时器组件

然后回到编程视图,将枚举法的代码加以修改,如图3所示。为了便于比较,修改了循环变量的起始值及终止值。

图3 记录枚举法求解所消耗的时间

这里需要解释一下计时器的“系统时间”,它取的是从1970年1月1日0时起至今的毫秒数(1000毫秒等于1秒),在上述代码中,分别提取程序运行起始和终止时的毫秒数,两者的差就是程序的运行时长,单位为毫秒。将时间差显示在屏幕的标题栏中,以便于比较。

测试结果如图4所示,运算耗时为2451毫秒。

图4  枚举法耗时2351毫秒

下面再修改直取法(图1)的代码,获取程序运行时间,如图5所示。

图5 修改直取法的代码,以获得程序运行所消耗的时间

测试结果如图6所示。

图6 直取法的程序耗时

直取法所用时间为27毫秒,从数量级上讲,枚举法是直取法的100倍。

就“物不知数”这道题而言,无论采用哪一种解法,在时间的消耗上都不会太大的差别,因此,对于解题方法的选择显得无足轻重。然而在现实世界里,有许多计算任务对处理时间有着严苛的要求,举例来说,无人驾驶汽车,要求计算机在极短时间内完成数据的采集、处理、决策、响应等一系列任务,在这种情况下,每个环节数据处理方法的优劣都会影响整个任务的用时,从而直接影响乘车人的生命安全。无人驾驶汽车是人工智能技术的一种应用,人工智能技术的背后意味着海量数据的存储与处理,而面对如此巨大的计算任务,算法的优化可以起到四两拨千斤的作用,即,用人类的智能优化机器的智能,这才是面向未来的解决之道。

从另一方面讲,解决“物不知数”这类问题,枚举法是最容易想到的解法,它利用了计算机善于做简单重复任务的优势,把复杂的问题简单化。然而如果我们把目标停留在获得答案上,那么就失去了发展人类本身智能的机会,也失去了探究世界奥秘的乐趣。

最后,人类也需要向计算机学习,就像我们对这个问题的求解,计算机可以在短时间内给出众多的答案,而我们人类善于从这些看似无关的数据中找出某种规律。利用这些只有人类才能识别出来的规律,改进解题方法,从而提高计算机的工作效率,这正是本文想要表达的主题。

附图:程序给出的10个答案

注:本文已正式发表于《爱上机器人》杂志总第2期(2018.09)。

(0)

相关推荐