《编程之美》笔记之——24点游戏

原著中给出了两种解法:穷举和分治。后来加上去除冗余括号等操作,自己写了四个实现代码,但完全还是用的原著中的算法思想。暂且把自己的实现过程记录下来。

自己的第一种代码实现,完全穷举,没有任何的优化。代码写得极其笨拙。程序穷举了四个数字能组成的所有可能的算式,分别计算它们的值,找到结果是24的那个算式,输出它。一个不带括号的算式总是有形式a op1 b op2 c op3 d,其中a,b,c,d是运算数,op1,op2,op3是运算符。代码中一个三重循环穷举三个运算符的43种组合,然后在每种组合下再穷举四个运算数的所有4!种排列,这样便得到了一个没有括号的算式。然后穷举五种加括号的形式,逐个判断值是否为24。这个过程中唯一值得回忆和感兴趣的是四个运算数五种不同加括号方式的由来。这是一个经典的Catalan数问题。

这个经典Catalan数问题在组合数学教材上都能找到。原题目是:n 个数相乘, 不改变它们的位置, 只用括号表示不同的相乘顺序,令g(n)表示这种条件下构成不同乘积的方法数,令C(n)表示第n个Catalan数。则有g(n)=C(n-1)。前几个Catalan数为:C(0)=1,C(1)=1,C(2)=2,C(3)=5,C(4)=14,C(5)=42。所以g(4)=C(3)=5。根据Catalan数的计算公式,有g(4)=g(1)g(3)+g(2)g(2)+g(3)g(1)。Catalan数的计算公式也同时提供了构造答案的方法。对于4个数,中间有3个位置,可以在任何一个位置一分为二,被分开的两半各自的加括号方案再拼凑起来就得到一种4个数的加括号方案:

只有一个数时:(A),一种

两个数:g(2)=g(1)g(1),所以是(A)(B)=(AB),一种

三个数:g(3)=g(1)g(2)+g(2)g(1)=(A)(BC)+(AB)(C),两种

四个数:g(4)=g(1)g(3)+g(2)g(2)+g(3)g(1)

                 =(A)[(B)(CD)+(BC)(D)]+(AB)(CD)+[(A)(BC)+(AB)(C)](D)

                 =A(B(CD)) + A((BC)D) + (AB)(CD) + (A(BC))D + ((AB)C)D

共有五种。于是写代码枚举这五种加括号的方式即可。这种方法只是一种能得到正确答案的方法,扩展性和效率都极差。而且生成的表达式中也有冗余括号。

同样是这种思想,《编程之美》上给出了一种优化的实现方法。一个算术表达式,无论如何复杂,总是按照优先级取出两个运算数进行运算得到一个中间结果,把这个中间结果加入到原表达式中,不断重复这一过程,直到剩下一个数。根据这个思想,可以很快写出实现代码。《编程之美》上即给出了一个完整的代码。

第二种实现的效率和扩展性显然不是第一种能比的。把两个数之间的一次加、减、乘、除看作一次基本运算。那么第一种实现要穷举四种运算符可重复的3组合,有43种,然后4个运算数的全排列,有4!种,之后5种不同的加括号方案,第种括号下要进行3次运算。总共需要做:43*4!*5*3=23040次基本运算。在第二种实现中,假设T(n)表示n个数要进行的基本运算次数,则T(1)=0, T(2) = 6, T(n)=C(n,2)*[6 + 6*T(n-1)]。其中C(n,2)表示n个数中取2个数的组合数。在第二种实现中,对于每一个2-组合,都要做6次基本运算,然后得到6个n-1个数的子问题。所以有上述公式。根据T(n)的公式,T(3)=126, T(4)=4572,所以在第二种实现方法中,穷举4个数的24点问题最多需要做4572次基本运算,这远低于第一种实现的23040次。

第二种实现所需要穷举的基本运算次数公式T(n)写成下面的形式更好看:

例如T(4)=C(4,2)*6+C(4,2)*6*C(3,2)*6+C(4,2)*6*C(3,2)*6*C(2,2)*6,这个形式让人感觉更有规律。那么有个问题:T(n)的最小值是多少?第二种实现有没有冗余计算?对于冗余计算,我觉得应该说,第二种实现可能会产生重复的计算,在4个运算数有重复的时

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值