如何对 3 个整数执行所有可能的算术运算组合?

How to perform all possible combinations of arithmetic operations on 3 integers?

假设我有三个整数。我想获得通过在它们之间执行所有 16(*, /, +, - 的 4x4)操作获得的所有可能值的列表。

就像我有 3 4 1,我们应该得到值 1、2、6、7、8、9、11、12, 13、15和16。即

res = num1 (op1) num2 (op2) num3 其中运算符为:

["**", "*/", "*+", "*-", "/*", "//", "/+", "/-", "+*", "+/", "++", "+-", "-*", "-/", "-+", "--"]

However, the catch is that division can only be possible if x%y==0 i.e. divisor is factor of dividend.

所以,到目前为止,我已经能够暴力破解每一个操作,但缺少一些答案。我还定义了一个自定义除法运算以考虑 捕获量

我需要 return 一个包含所有正值的唯一值的列表。


我目前的代码很乱,但这是为了它。这也遗漏了一些值。

def div(x, y):
    if x!=0 and y!=0:
        if x%y==0:return x/y
        else:return None


ops_lis = ["**", "*/", "*+", "*-", "/*", "//", "/+", "/-", "+*", "+/", "++", "+-", "-*", "-/", "-+", "--"]

d1, d2, d3 = map(int, input().split())
cal_lis, res_lis = [], []
for op in ops_lis:
    if op[0] == "*" and op[1] == "*":cal_lis.append(d1*d2*d3)
    if op[0] == "*" and op[1] == "/":
        if div(d1*d2, d3) != None:cal_lis.append(div(d1*d2, d3))
        cal_lis.append(div(d1*d2, d3))
    if op[0] == "*" and op[1] == "+":
        cal_lis.append(d1*(d2+d3))
        cal_lis.append((d1*d2)+d3)
    if op[0] == "*" and op[1] == "-":
        cal_lis.append(d1*d2-d3)
        cal_lis.append(d1*(d2-d3))
        cal_lis.append((d1*d3)-d2)
    if op[0] == "/" and op[1] == "*":cal_lis.append(div(d1, d2*d3))
    if op[0] == "/" and op[1] == "/":
        if div(d1, d2) == None or div(d2, d3) == None:
            cal_lis.append(None)
        else:
            cal_lis.append(div(div(d1, d2), d3))
    if op[0] == "/" and op[1] == "+":
        if div(d1, d2) == None:
            cal_lis.append(None)
        else:
            cal_lis.append(div(d1, d2)+d3)
    if op[0] == "/" and op[1] == "-":
        if div(d1, d2) == None:
            cal_lis.append(None)
        else:
            cal_lis.append(div(d1, d2)-d3)

    if op[0] == "+" and op[1] == "*":
        cal_lis.append(d1+d2*d3)
        cal_lis.append((d1+d2)*d3)
        cal_lis.append((d1+d3)*d2)
    if op[0] == "+" and op[1] == "/":
        if div(d2, d3) == None:
            cal_lis.append(None)
        else:
            cal_lis.append(d1+div(d2, d3))
    if op[0] == "+" and op[1] == "+":cal_lis.append(d1+d2+d3)
    if op[0] == "+" and op[1] == "-":cal_lis.append(d1+d2-d3)

    if op[0] == "-" and op[1] == "*":
        cal_lis.append(d1-d2*d3)
        cal_lis.append((d1-d2)*d3)
        cal_lis.append((d1-d3)*d2)
    if op[0] == "-" and op[1] == "/":
        if div(d2, d3) == None:cal_lis.append(None)
        else: cal_lis.append(d1-div(d2, d3))
        if div(d1-d2, d3) == None:cal_lis.append(None)    
        else: cal_lis.append(div(d1-d2, d3))
    if op[0] == "-" and op[1] == "+":cal_lis.append(d1-d2+d3)
    if op[0] == "-" and op[1] == "-":cal_lis.append(d1-d2-d3)

# print(cal_lis)
cal_lis = [int(cal) for cal in cal_lis if cal!=None]
for res in cal_lis:
    if (res > 0 and res not in res_lis):
        res_lis.append(int(res))
for a in sorted(res_lis):
    print(a, end=" ")
print()

鉴于划分条件也为真,是否有一种有效的方法来执行此任务(也许使用树?)?

如有任何帮助,我们将不胜感激...


编辑:添加约束

计算必须符合以下格式: number = dice1 op1 dice2 op2 dice3

其中:

您可以使用

nums = [34, 12, 6]

itertools.combinations_with_replacement(ops_lis, len(nums) - 1)

您可以使用以下方法获取操作数的所有排列:

itertools.permutations(nums)

然后您可以使用三个嵌套循环构建所有可能的表达式,并使用 eval() 计算表达式。

获取运算符的所有组合。

这是我的快速解决方案。 我正在使用 np.nan,它在任何计算后都将保持为 np.nan,因此我们可以识别不满足条件的组合。

import numpy as np
import itertools

def plus(a, b):
    return a + b

def minus(a, b):
    return a - b

def mult(a, b):
    return a * b

def div(a, b):
    if b!=0:
        if a%b==0:
            return a//b
    return np.nan


def combinations(nums, funcs):
    t = []
    for i in range(len(nums)-1):
        t.append(nums)
        t.append(funcs)
    t.append(nums)
    return list(itertools.product(*t))

def solve(instance):
    instance = list(instance)
    for i in range(len(instance)//2):
        b = instance.pop()
        func = instance.pop()
        a = instance.pop()
        instance.append(func(a, b))
    return instance[0]

def main():
    a = [1, 3 ,4]
    func = [plus, minus, mult, div]
    combs = combinations(a, func)
    solutions = [solve(i) for i in combs]
    for i, j in zip(combs, solutions):
        print(i, j)



if __name__ == "__main__":
    main()

它是从右到左求解运算,但您可以根据需要更改求解函数。

这是一个解决方案,它使用 itertools 来生成两个运算符的每个组合,并使用 Python 的 eval 来评估字符串。

from itertools import product
ops = ['+', '-', '*', '/']
nums = [3, 4, 0]

combos = product(ops, repeat=2)
for expr in combos:
        eval_me = f'{nums[0]} {expr[0]} {nums[1]} {expr[1]} {nums[2]}'
        try:
            result = eval(eval_me)
            print (f'{eval_me} = {result}')
        except ZeroDivisionError as e:
            print (f'expression "{eval_me}" caused an exception: {e}')

使用 4 个运算符,我们有 4 * 4 = 16 个结果。

结果如下:

3 + 4 + 0 = 7
3 + 4 - 0 = 7
3 + 4 * 0 = 3
expression "3 + 4 / 0" caused an exception: division by zero
3 - 4 + 0 = -1
3 - 4 - 0 = -1
3 - 4 * 0 = 3
expression "3 - 4 / 0" caused an exception: division by zero
3 * 4 + 0 = 12
3 * 4 - 0 = 12
3 * 4 * 0 = 0
expression "3 * 4 / 0" caused an exception: division by zero
3 / 4 + 0 = 0.75
3 / 4 - 0 = 0.75
3 / 4 * 0 = 0.0
expression "3 / 4 / 0" caused an exception: float division by zero

要获得所有可能的结果,您需要在组合中包含操作分组。我建议为此使用递归函数:

def calcAll(*values,seen=None):
    seen = seen or set()
    if len(values) == 2:
        a,b  = values
        a,sa = (a[0],f"({a[1]})") if isinstance(a,tuple) else (a,str(a))
        b,sb = (b[0],f"({b[1]})") if isinstance(b,tuple) else (b,str(b))
        if a>b : a,sa, b,sb = b,sb, a,sa
        if (a,b) in seen or seen.add((a,b)) :return                
        yield a+b, f"{sa}+{sb}"
        yield a*b, f"{sa}*{sb}"
        yield a-b, f"{sa}-{sb}"
        yield b-a, f"{sb}-{sa}"
        if b != 0 and a%b==0: yield a//b, f"{sa}/{sb}"
        if a != 0 and b%a==0: yield b//a, f"{sb}/{sa}"
        return
    pairs = ((i,j) for i in range(len(values)-1) for j in range(i+1,len(values)))
    for i,j in pairs:
        rest = [*values]
        a,b  = rest.pop(j),rest.pop(i)
        for paired in calcAll(a,b,seen=seen):            
            for result in calcAll(paired,*rest):
               if result in seen or seen.add(result): continue
               yield result

输出:

# distinct positive solutions sorted by result
for r,sr in sorted(calcAll(3,4,1)):
    if r>0: print(sr,"=",r)

(1*4)-3 = 1
4-(3/1) = 1
(4/1)-3 = 1
(4-3)*1 = 1
4/(1+3) = 1
4-(1*3) = 1
(4-3)/1 = 1
1/(4-3) = 1
3/(4-1) = 1
(1+3)/4 = 1
(4-1)/3 = 1
1-(3-4) = 2
4-(3-1) = 2
(1+4)-3 = 2
(1-3)+4 = 2
(4-3)+1 = 2
4/(3-1) = 2
(4-1)+3 = 6
(3-1)+4 = 6
3-(1-4) = 6
4-(1-3) = 6
(4+3)-1 = 6
(1*4)+3 = 7
(3/1)+4 = 7
(4/1)+3 = 7
(1*3)+4 = 7
(4+3)/1 = 7
(4+3)*1 = 7
(1+4)+3 = 8
(1+3)+4 = 8
(3-1)*4 = 8
(4+3)+1 = 8
(4-1)*3 = 9
(4*3)-1 = 11
(1*4)*3 = 12
(4*3)*1 = 12
(4*3)/1 = 12
(1*3)*4 = 12
(3/1)*4 = 12
(4/1)*3 = 12
(4*3)+1 = 13
(1+4)*3 = 15
(1+3)*4 = 16

如果您只想要明显的积极结果:

print( set(r for r,_ in calcAll(3,4,1) if r>0) )
{1, 2, 6, 7, 8, 9, 11, 12, 13, 15, 16}

该函数也适用于较大的数字列表:

# one solution for each positive result of operations between 4 numbers
for r,sr in sorted(dict(calcAll(1,2,3,4)).items()):
    if r>0: print(sr,"=",r)
(2/1)+(3-4) = 1
(2-1)-(3-4) = 2
(2/1)-(3-4) = 3
(4*3)/(2+1) = 4
((4*3)/2)-1 = 5
(4*3)/(2/1) = 6
((4*3)/2)+1 = 7
(4+3)-(1-2) = 8
(4*3)-(2+1) = 9
(4*3)-(2/1) = 10
(1-2)+(4*3) = 11
(4*3)/(2-1) = 12
(4*3)-(1-2) = 13
(2/1)+(4*3) = 14
(2+1)+(4*3) = 15
(1+(4+3))*2 = 16
(3*(4+2))-1 = 17
(3/1)*(4+2) = 18
(3*(4+2))+1 = 19
((3*2)-1)*4 = 20
(2+1)*(4+3) = 21
((4*3)-1)*2 = 22
(2*(4*3))-1 = 23
(2/1)*(4*3) = 24
(2*(4*3))+1 = 25
(1+(4*3))*2 = 26
(1+(4*2))*3 = 27
(1+(3*2))*4 = 28
(4+1)*(3*2) = 30
(3+1)*(4*2) = 32
(2+1)*(4*3) = 36        

还有重复的数字:

for r,sr in sorted(dict(calcAll(3,3,3)).items()):
    if r>0: print(sr,"=",r)

3-(3/3) = 2
3/(3/3) = 3
(3/3)+3 = 4
(3*3)-3 = 6
(3+3)+3 = 9
(3*3)+3 = 12
(3+3)*3 = 18
(3*3)*3 = 27