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

解法二也用到了分治思想,只是解法一是从合并数据开始的,解法二它从一开始便拆分数据,最后要合并数据才能看到结果。

解法二相对解法一的优点是减少了冗余计算,缺点当然是数据管理麻烦。

posted on 2012-10-25 15:41  罗辑  阅读(232)  评论(0编辑  收藏  举报