24点
- 代码
- 说明
- 验证
- 贪心算法
- 代码
- 验证
高斯9岁的时候遇到了老师出的从1加到100.现在三年级的学生有24点的数学活动。
代码
from itertools import combinations
import re
class Solver:
target = 24
ops=['+', "-", "*", "/", "--", "//"]
def __init__(self, precise_mode=False):
self.precise_mode = precise_mode
def solution(self, nums):
result = []
groups = self.dimensionality_reduction(self.format(nums))
for group in groups:
for op in self.ops:
exp = self.assemble(group[0], group[1], op)["exp"]#直接使用返回的字典键值‘exp’
if self.check(exp, self.target) and exp not in result:
result.append(exp)
return [exp + "=" + str(self.target) for exp in result]
def dimensionality_reduction(self, nums):
result = []
if len(nums) > 2:
for group in self.group(nums, 2):
for op in self.ops:
new_group = [self.assemble(group[0][0], group[0][1], op)] + group[1]
#print(new_group)
result += self.dimensionality_reduction(new_group)
else:
result = [nums]
return result
def assemble(self, exp1, exp2, op):
if op == "--" or op == "//":
return self.assemble(exp2, exp1, op[0])
if op in r'*/':
exp1 = self.add_parenthesis(exp1)
exp2 = self.add_parenthesis(exp2)
if self.precise_mode:
if op == "-":
exp2 = self.add_parenthesis(exp2)
elif op == "/":
exp2 = self.app_parenthesis(exp2, True)
exp = self.convert(exp1["exp"] + op + exp2["exp"], op)
return{"op":op, "exp":exp}
def add_parenthesis(self, exp, is_necessary=False):
if(is_necessary and not exp["exp"].isdigit()) or exp["op"] in r"+-":
result={"exp":"(" + exp["exp"] + ")", "op":exp["op"]}
else:
result = exp
return result
def check(self, exp, target, precision=0.0001):
try:
#print("exp",exp)
return abs(eval(exp) - target) < precision
except ZeroDivisionError:
return False
def convert(self, exp, op):
#print("exp",exp,op)
if op in r"+-":#(\(.+\)|\d+)[\*\/](\(.+\)\d+)
#r"()"捕获,[\+\-]一组字符正负±号,(\(.+\)|\d+)分组一,(.+)或者多次出现的数字,
#[\*\/]一组乘或除,|\d两者任一
pattern = r"([\+\-]((\(.+\)|\d+)[\*\/](\(.+\)\d+)|\d))"
exp = "+" + exp
else:
#[\*\/](\(.+\)|d+)
#(\(.+\)|d+)
#\(.+\)有括号包着的式子,'.'任何字符(换行符除外),'+'一次或多次出现
#pattern=r"([\*\/](\(.+?\)|d+))" 这里的问号不要也可以的。
pattern = r"([\*\/](\(.+\)|d+))"
exp = "*" + exp
#for i in re.findall(pattern,exp):
# print(i)
#Python join() 方法用于将序列中的元素以指定的字符连接生成一个新的字符串。
result = "".join(sorted([i[0] for i in re.findall(pattern, exp)]))
#print("result",result)
if len(result) != len(exp):
result = exp
return result[1:]
def format(self, nums):
return [{"op": " ", "exp":str(num)} for num in nums]
def group(self, exp_list, counter):
index_list = [i for i in range(len(exp_list))]
#print("index_list",index_list)
combination = list(combinations(index_list, counter))
#print("combination",combination)
for group1 in combination:
group2 = list(set(index_list) - set(group1))
#print("group2",group2)
yield [[exp_list[g1] for g1 in group1], [exp_list[g2] for g2 in group2]]
#help(eval)
#help(combinations)
auto_input = True
if auto_input:
from numpy import random
customer_input = random.randint(1, 20, 4)
else:
customer_input = list()
customer_input.append(input("请输入第一个数字:"))
customer_input.append(input("请输入第二个数字:"))
customer_input.append(input("请输入第三个数字:"))
customer_input.append(input("请输入第四个数字:"))
task = Solver()
answer = task.solution(customer_input)
if len(answer) == 0:
print("No solutions")
else:
for a in answer:
print(a)
直接运行生成的是17、2、17、12四个随机数。
说明
1、format:{“op”: " ", “exp”:str(num)}每个数字格式化成操作数、表达式的格式。
[{‘op’: ’ ', ‘exp’: ‘17’}, {‘op’: ’ ', ‘exp’: ‘2’}, {‘op’: ’ ', ‘exp’: ‘17’}, {‘op’: ’ ', ‘exp’: ‘12’}]
2、dimensionality_reduction列出所有的算术组合:
groups有481行:
[…
[{‘op’: ‘+’, ‘exp’: ‘17+2’}, {‘op’: ‘/’, ‘exp’: ‘12/17’}],
[{‘op’: ‘-’, ‘exp’: ‘17-2’}, {‘op’: ‘/’, ‘exp’: ‘12/17’}],
[{‘op’: ‘’, ‘exp’: '172’}, {‘op’: ‘/’, ‘exp’: ‘12/17’}],
[{‘op’: ‘/’, ‘exp’: ‘17/2’}, {‘op’: ‘/’, ‘exp’: ‘12/17’}],
[{‘op’: ‘-’, ‘exp’: ‘2-17’}, {‘op’: ‘/’, ‘exp’: ‘12/17’}],
[{‘op’: ‘/’, ‘exp’: ‘2/17’}, {‘op’: ‘/’, ‘exp’: ‘12/17’}]]
3、assemble组合四则运算:
怎么还有减减除除的情况。注掉看看
#if op == "--" or op == "//":
# return self.assemble(exp2, exp1, op[0])
如下是注释后的结果与正确的验证结果的比较。
第五个的减减17要改成加。
17+2-12–17=24 #注掉的情况
17-12+17+2=24
第九个的除除17要放到最后除17
172//1712=24 #注掉的情况
17212/17=24
#下面的代码没有走到的。
#if self.precise_mode:
# if op == "-":
# exp2 = self.add_parenthesis(exp2)
# elif op == "/":
# exp2 = self.app_parenthesis(exp2, True)
4、add_parenthesis加括号
5、convert:
把组合后的两个表达式转成{“op”:op, “exp”:exp}的格式。
6、check计算算术表达式。
验证
17+2+17-12=24
(17+2-17)*12=24
(17-17+2)*12=24
17+2-12+17=24
17-12+17+2=24
12/17*2*17=24
17*2/17*12=24
17/17*2*12=24
17*2*12/17=24
17*12/17*2=24
12/17*17*2=24
(2-17+17)*12=24
2/17*17*12=24
2/17*12*17=24
17*12*2/17=24
17+17+2-12=24
17+17-12+2=24
(12-17+17)*2=24
2-12+17+17=24
2*12-17+17=24
(17-17+12)*2=24
2*12+17-17=24
2*12/17*17=24
17/17*12*2=24
2*12*17/17=24
(17+12-17)*2=24
17-12+2+17=24
2+17+17-12=24
2*17/17*12=24
2*17*12/17=24
(2+17-17)*12=24
2+17-12+17=24
17-17+2*12=24
这里面有很多重复的答案,小孩只要一个答案就可以了,那就是贪心算法。
贪心算法
代码
def f(nums, road=[], n=4):
'''Breadth first, returns in the middle?
Compare and return, it may be depth first,
and it is a recursive call,not a while queue operation
'''
if 1 == n:
return abs(nums[0] - 24) < 0.0000001
new_nums = [0] * 4
for left in range(n - 1):
for right in range(left + 1, n):
index = 0
#Move non computed numbers to the front of the array
for i in range(n):
if nums[left] != nums[i] and nums[right] != nums[i]:
new_nums[index] = nums[i]
index += 1
#Put the computed result last
#+
new_nums[index] = nums[left] + nums[right]
temp = repr(nums[left]) + '+' + repr(nums[right]) + '=' + repr(new_nums[index])
road.append(temp)
if f(new_nums, road, index + 1): return True
road.pop()
#-
new_nums[index] = nums[left] - nums[right]
temp = repr(nums[left]) + '-' + repr(nums[right]) + '=' + repr(new_nums[index])
road.append(temp)
if f(new_nums, road, index + 1): return True
road.pop()
#-
new_nums[index] = nums[right] - nums[left]
temp = repr(nums[right]) + '-' + repr(nums[left]) + '=' + repr(new_nums[index])
road.append(temp)
if f(new_nums, road, index + 1): return True
road.pop()
#*
new_nums[index] = nums[left] * nums[right]
temp = repr(nums[right]) + '*' + repr(nums[left]) + '=' + repr(new_nums[index])
road.append(temp)
if f(new_nums, road, index + 1): return True
road.pop()
#/
if 0 != new_nums[right]:
new_nums[index] = nums[left] / nums[right]
temp = repr(nums[right]) + '/' + repr(nums[left]) + '=' + repr(new_nums[index])
road.append(temp)
if f(new_nums, road, index + 1): return True
road.pop()
if 0 != new_nums[left]:
new_nums[index] = nums[right] / nums[left]
temp = repr(nums[left]) + '/' + repr(nums[right]) + '=' + repr(new_nums[index])
road.append(temp)
if f(new_nums, road, index + 1): return True
road.pop()
return False
nums=[8,7,4,1,]
while True:
nums[0] = int(input('输入数字:'))
nums[1] = int(input('输入数字:'))
nums[2] = int(input('输入数字:'))
nums[3] = int(input('输入数字:'))
road=[]
print(nums)
print(f(nums, road))
print(road)
验证
输入数字:17
输入数字:2
输入数字:17
输入数字:12
[17, 2, 17, 12]
True
[‘17+17=34’, ‘2-12=-10’, ‘34±10=24’]
贪心算法等到了一个解。
![]() |
---|