draak

导航

python(第三周作业)续上

算24

描述

给出4个小于10的正整数,可以使用加、减、乘、除4种运算以及括号把4个数连接起来得到一个表达式。现在问题是,是否存在一种方式使得所得表达式的结果等于24。‪‬‪‬‪‬‪‬‪‬‮‬‪‬‮‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‭‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‫‬

这里加、减、乘、除以及括号的运算结果和运算优先级跟平常定义一致。‪‬‪‬‪‬‪‬‪‬‮‬‪‬‮‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‭‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‫‬

         例如,对于5,5,5,1,可知5×(5-1/5)=24。又如,对于1,1,4,2无论如何都不能得到24

输入格式

     在代码中的输入部分输入4个小于10的正整数。输入使用input(),不要增加额外的提示信息。‪‬‪‬‪‬‪‬‪‬‮‬‪‬‮‬‪‬‪‬‪‬‪‬‪‬‮‬‪‬‪‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‭‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‫‬‪‬‪‬‪‬‪‬‪‬‮‬‫‬‫‬

输出格式

      对于每一组测试数据,输出一行,如果可以得到24,输出"YES"其算法;否则“NO”。

 1 from itertools import permutations
 2 a = input()
 3 b = input()
 4 c = input()
 5 d = input()
 6 n = a+b+c+d
 7 sum = 1
 8 for i in n:
 9     sum *= eval(i)
10 if sum < 24:
11     print("NO")
12     exit()
13 notation = ['+', '-', '*', "/"]
14 st = set()
15 num = 0
16 number = set(permutations(n))#将n进行相应的排列组合
17 for i in notation:
18     s = i
19     t1 = notation.copy()
20     t1.remove(i)#进行一次就去掉一个运算符
21     for j in t1:
22         s += j
23         t2 = t1.copy()
24         t2.remove(j)
25         for p in t2:
26             s += p
27             st.add(s)
28             s = i+j
29         s = i
30 newst = set()
31 for i in number:
32     for j in st:
33         newst.add(i[0]+j[0]+i[1]+j[1]+i[2]+j[2]+i[3])
34 # print(newst)
35 all = set()
36 for i in newst:
37     i1 = '('+i[0:3]+')'+i[3:]
38     i2 = i[0:2]+'('+i[2:5]+')'+i[5:]
39     i3 = i[0:4] + '(' + i[4:] + ')'
40     i4 = '(('+i[0:3]+')'+i[3:5]+")"+i[5:]
41     i5 = i[0:2]+'(('+i[2:5]+')'+i[5:]+")"
42     i6 = '(' + i[0:2] + '(' + i[2:5] + '))' + i[5:]
43     i7 = i[0:2]+'('+i[2:4]+'('+i[4:]+"))"
44     all.add(i1)
45     all.add(i2)
46     all.add(i3)
47     all.add(i4)
48     all.add(i5)
49     all.add(i6)
50     all.add(i7)
51 result = []
52 for i in all:
53     try:
54         if eval(i) == 24:
55           result.append(i)
56     except:
57         pass
58 print("YES")
59 print("("+sorted(result)[0]+")")
View Code

计算24点在打扑克的时候会用到呢

网上挺多计算24点的小窍门,根据所给的公式用python转换出来就可以用啦,代码如上👆!

另外一种计算24点的代码,如下👇,是我在简书上看到的,在那基础上修改了一下

from __future__ import division
from itertools import combinations
import re


class Solver:

    # 需要达成的目标结果值
    target = 24

    # 四则运算符号定义,其中,a -- b = b - a,a // b = b / a
    ops = ['+', '-', '*', '/', '--', '//']

    # precise_mode为精准模式,若开启,则减号及除号后开启括号
    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']
                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 = []

        # 如果维数大于2,则选出两个表达式组合成一个,从而降低一个维度,通过递归降低到二维
        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]
                    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.add_parenthesis(exp2, True)

        exp = self.convert(exp1['exp'] + op + exp2['exp'], op)
        return {'op': op, 'exp': exp}

    # 根据需要为表达式添加相应的括号
    @staticmethod
    def add_parenthesis(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

    # 检查表达式是否与结果相等,考虑到中间步骤的除法,因此不采用相等判断,而是采用计算值和目标值的绝对值是否符合某个精度
    @staticmethod
    def check(exp, target, precision=0.0001):
        try:
            return abs(eval(exp) - target) < precision
        except ZeroDivisionError:
            return False

    # 将表达式各项重新排序成为等价标准表达式
    @staticmethod
    def convert(exp, op):
        if op in r'+-':
            pattern = r'([\+\-]((\(.+\)|\d+)[\*\/](\(.+\)|\d+)|\d+))'
            exp = '+' + exp
        else:
            pattern = r'([\*\/](\(.+?\)|\d+))'
            exp = '*' + exp
        result = ''.join(sorted([i[0] for i in re.findall(pattern, exp)]))
        if len(result) != len(exp):
            result = exp
        return result[1:]

    # 将输入的数字格式化为字典,数字的运算符号为空格,注意不是空字符
    @staticmethod
    def format(nums):
        return [{'op': ' ', 'exp': str(num)} for num in nums]

    # 对表达式列表进行分组,返回列表,[[[n1, n2], [n3, n4]], [[n1, n3], [n2, n4]], ...]
    @staticmethod
    def group(exp_list, counter):

        # 生成以下标号为元素的列表
        index_list = [i for i in range(len(exp_list))]

        # 以下标号列表取出不重复的组合
        combination = list(combinations(index_list, counter))

        # 使用下标得到原表达式并组成最终的结果数组
        for group1 in combination:
            group2 = list(set(index_list) - set(group1))
            yield [
                [exp_list[g1] for g1 in group1],
                [exp_list[g2] for g2 in group2]
            ]

auto_input = True
if auto_input:
    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')
else:
    for a in answer:
        print("YES")
        print(a)
        break  #加入break只会出现第一种符合abcd复合运算=24的式子
View Code

加了break的效果

 

不加break的效果

 

愿我们少掉点头发!

 

posted on 2020-03-26 17:03  c-pig  阅读(443)  评论(0编辑  收藏  举报