1.16 24点游戏
题意:给定4个数,运用加减乘除和括号,构造多项式,使得结果等于24。
解法一是穷举法,四个数字有4!排列,运算符号有43种可能,外加5种加括号的方式。
为什么是5种?书上没说,推断如下:
括号决定先算什么,最先需要算的两个数决定了3种可能组合,那么我们可以得到:
ABCD->(AB)CD, A(BC)D, AB(CD)
把一个括号内的看成一个数字,那可以认为,上一步把4个数字变成了3个,现在需要把3个数字变两个,那么可以继续:
(AB)CD->((AB)C)D, (AB)(CD)
A(BC)D->(A(BC))D, A((BC)D)
AB(CD)->(AB)(CD), A(B(CD))
两个数字已经无关优先级了,分解到此为止。从得到的6个结果中,由于(AB)(CD)重复了一次,所以有5种可能的方案。
下面贴上Python代码,也是分治的思想写的,不过比书中的要清晰一些。
from timeit import itertools def game24(v): l = len(v) - 1 if l == 0: return True if abs(v[0] - 24) < 1e-6 else False ret = False for i in range(l): a, b, c, d = v[i] + v[i + 1], v[i] - v[i + 1], v[i] * v[i + 1], v[i] / v[i + 1] if v[i + 1] != 0 else None av, bv, cv, dv = v[:], v[:], v[:], v[:] av[i], bv[i], cv[i], dv[i] = a, b, c, d del av[i + 1] del bv[i + 1] del cv[i + 1] del dv[i + 1] ret = game24(av) or game24(bv) or game24(cv) or game24(dv) if dv[i] != None else False if ret: break return ret if __name__ == '__main__': v = [9, 4, 2, 1] ret = False for p in itertools.permutations(v): if game24(list(p)): ret = True break print ret
解法二也用到了分治思想,只是解法一是从合并数据开始的,解法二它从一开始便拆分数据,最后要合并数据才能看到结果。
解法二相对解法一的优点是减少了冗余计算,缺点当然是数据管理麻烦。