# “24点”的算法分析

## 算法分析

### 分拆集合

 def enumerateAllSubsets(elements) : def appendElement(orig_subsets, element) : result = [] for set in orig_subsets : result.append(set) tmp = [] for ele in set : tmp.append(ele) tmp.append(element) result.append(tmp) return result result = [[]] for e in elements : result = appendElement(result, e) for e in result : e.sort() return result

enumerateAllSubsets所返回的子集集合并不能直接用于24点的计算，因此我们必须先做一些准备工作——去除空集和全集。由于集合中可能会有重复的数字，为了减少运算量，我们还要去除重复的子集。

 def getSets (elements): elements.sort() tmp_result = enumerateAllSubsets(elements) tmp_result.remove([]) tmp_result.remove(elements) result = [] for e in tmp_result : e.sort() try: result.index(e) except ValueError: result.append(e) return result

 def suppSet (fullSet, subSet): result = [] for item in fullSet : # 由于可能会有重复的元素，因此不能写 result.append(item) # for item in fullSet: for item in subSet : # if not item in subSet : result.remove(item) # result.append(item) return result

### 构造算式

 ADD = "+" MIN = "-" MUL = "*" DIV = "/" TYPE_OF_NUMBERS = (type(1), type(1.0)) class equationTree(object) : def __init__ (self, left_tree, operator=None, right_tree=None): self.left_tree = left_tree self.right_tree = right_tree self.operator = operator def value (self): if not self.operator : return float(self.left_tree) else: if type(self.left_tree) in TYPE_OF_NUMBERS: str_to_calc = str(float(self.left_tree)) else: str_to_calc = str(self.left_tree.value()) str_to_calc += self.operator if type(self.right_tree) in TYPE_OF_NUMBERS: str_to_calc += str(float(self.right_tree)) else: str_to_calc += str(self.right_tree.value()) try: ## 1. 出现 ZeroDivError的时候，这个算式的值就为None ## 2. 这要这个算式的某一部分的值为None，那么这个算式的值就是None result = eval(str_to_calc) except : result = None return result def __repr__ (self): if type(self.left_tree) in TYPE_OF_NUMBERS : left_repr = str(self.left_tree) else: left_repr = self.left_tree if type(self.right_tree) in TYPE_OF_NUMBERS : right_repr = str(self.right_tree) else: right_repr = self.right_tree if not self.operator : return left_repr else: if self.operator == ADD: pass elif self.operator == MIN: if type(self.right_tree) not in TYPE_OF_NUMBERS and self.right_tree.operator in (ADD, MIN): right_repr = "(" + right_repr + ")" elif self.operator == MUL: if type(self.left_tree) not in TYPE_OF_NUMBERS and self.left_tree.operator in (ADD, MIN) : left_repr = "(" + left_repr + ')' if type(self.right_tree) not in TYPE_OF_NUMBERS and self.right_tree.operator in (ADD, MIN): right_repr = "(" + right_repr +')' else: if type(self.right_tree) not in TYPE_OF_NUMBERS and self.right_tree.operator : right_repr = "(" + right_repr + ')' if type(self.left_tree) not in TYPE_OF_NUMBERS and (self.left_tree.operator in (ADD, MIN)): left_repr = "(" + left_repr + ')' return left_repr + self.operator + right_repr

### 枚举算式

 def getEqTrees (elements): if len(elements) == 1 : return [equationTree(elements[0])] elif len(elements) == 2: return [equationTree(elements[0], ADD, elements[1]), equationTree(elements[0], MIN, elements[1]), equationTree(elements[0], MUL, elements[1]), equationTree(elements[0], DIV, elements[1]), equationTree(elements[1], MIN, elements[0]), equationTree(elements[1], DIV, elements[0]),] else: result = [] for e in getSets(elements): for left_tree in getEqTrees(e) : for right_tree in getEqTrees(suppSet(elements, e)) : for op in (ADD, MIN, MUL, DIV) : result.append(equationTree(left_tree, op, right_tree)) return result

## 结尾

 if __name__ == '__main__' : print """ Written by shhgs, on March 3, 2004.""" result = [] print """ Please input a tuple of integer, delimited by colon. For example: 1, 2, 3, 4 Don't try to input more than 5 numbers, otherwise it will take a long long time to respond. Four is recommended. """ tup = input('Please input the tuple of integers: ') for eq in getEqTrees(list(tup)): if eq.value() == 24 : result.append(eq) print "%s = 24" % eq

[1]这个算法是用Python实现的，因此这里用Python的表示方法。有兴趣的读者可以试着用Java或其他语言来实现。

[2]这个程序里面有中文注释，所以运行的时候会出现警告。要想解决这个问题，可以在程序的第一行加上：

 # -*- coding: mbcs -*-

• 0
点赞
• 3
评论
• 0
收藏
• 一键三连
• 扫一扫，分享海报

08-01
04-13 5679

12-05 915
07-10 1652
03-10 710
01-04 1万+
11-04 7万+
09-05 13
07-30 1万+
08-28 552
06-02 1346
11-29 2万+
08-16 7795
03-01 4740
04-27 9989
09-11 450
06-10 52