三年级的24点

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’]
贪心算法等到了一个解。

三年级的24点验证过程
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值