使用随机数列表和所有简单数学运算符计算所有可能的组合以达到给定目标

时间:2015-04-14 16:07:58

标签: python algorithm math combinations

我正在编写一个简单的Python脚本,随机生成6个数字(从1到100)和一个更大的数字(从100到1000)。我对此脚本的目标是:

  1. 使用至少2个数字和任何简单的数学运算(加,减,乘和除)计算所有可能的组合

  2. 输出所有总数在10以上或以下的组合,以匹配'

  3. 数字列表不需要用尽,但重复的数字不被接受。如果代码有效或者没有效率,我也不会太在意(如果有人决定发布任何内容 - 如果有人需要,我可以发帖到目前为止 - 最好是用Python发布);只要它有效,我很乐意对其进行优化。

    我自己尝试过,只是因为程序快速以RunTime错误结束而失败。我也试过放入一个计数器来在x传递之后停止循环(其中x是一个很小的数字,比如50),但这会让事情变得更糟,因为它会继续无限地进行。

    我也做了一些研究,我发现这个(Computing target number from numbers in a set - 倒数第二个答案)是我发现的最接近我要求的但是还没到那里

    感谢您的帮助! : - )

    编辑:这是我的代码:

    import random, time, operator
    
    i = 0
    numlist = []
    while i != 6:
        number = random.randint(1, 100)
        numlist.append(number)
        i += 1
    
    largenumber = random.randint(100, 1000)
    print(numlist)
    print(largenumber)
    
    def operationTesting():
        a, c, m, total = 0, 0, 0, 0
        totalnums = 0
        operators = ['+', '-', '*', '/']
        while total != largenumber:
            for a in numlist[m]:
                for c in numlist[m+1]:
                    print(a)
                    print(c)
                    if a == c:
                        operationTesting()
                    else:
                        b = random.choice(operators)
                        if b == '+':
                            summednums = operator.add(int(a), int(c))
                            print(summednums)
                            totalnums = totalnums + summednums
                        elif b == '-':
                            summednums = operator.sub(int(a), int(c))
                            print(summednums)
                            totalnums = totalnums + summednums
                        elif b == '*':
                            summednums = operator.mul(int(a), int(c))
                            print(summednums)
                            totalnums = totalnums + summednums
                        elif b == '/':
                            summednums = operator.floordiv(int(a), int(c))
                            print(summednums)
                            totalnums = totalnums + summednums
                        print(totalnums)
                        SystemExit(None)
    
    operationTesting()
    

1 个答案:

答案 0 :(得分:2)

一种非常简洁的方法是使用Reverse Polish Notation or Postfix表示法。如果您使用带有运算符优先级等的常规算法,那么这种表示法可以避免使用您可能想要的括号。

如果你对时间效率不太感兴趣,你可以用蛮力做到这一点。你需要考虑你想要对分区做什么 - 如果两个数字没有完全分开,你想要将结果返回为“无效”'在某种程度上(我猜是这样),还是真的回归了一个分区?注意后者可能会给你一些无效的答案......

考虑numlist = [1,2,3,4,5,6]的测试用例。在RPN中,我们可以做这样的事情

RPN           Equivalent to
123456+++++   (1+(2+(3+(4+(5+6)))))
123456++++-   (1-(2+(3+(4+(5+6)))))
123456+++-+   (1+(2-(3+(4+(5+6)))))
...
12345+6+-++   (1+(2+(3-((4+5)+6))))
12345+6-+++   (1+(2+(3+((4+5)-6))))
...

等等。您可以看到,通过足够的组合,您可以获得数字,运算符和括号的任意组合。括号很重要 - 显然只需要3个数字

1+2*6 

通常被解释

(1 + (2*6)) == 13

完全不同
((1+2)*6) == 18

在RPN中,这些分别为126*+12+6*

因此,您必须在RPN中生成所有组合,然后开发RPN计算器来评估它们。

不幸的是,有6个数字(或其任何子集)存在相当多的排列。首先,您可以按任意顺序排列数字,即6! = 720组合。您将始终需要n-1 == 5个运营商,他们可以是4个运营商中的任何一个。那就是4**5 == 1024排列。最后,这5个操作员可以处于5个位置中的任何一个位置(在第一对数字之后,在第3对之后,在4之后,依此类推)。您可以在第一个位置拥有最多1个操作符,在第二个位置拥有两个,依此类推。这是5! == 120个排列。所以总共有720*1024*120 == 88473600个排列。大致9 * 10**7根本不超出计算领域,但可能需要5分钟左右才能在相当快的计算机上生成它们。

你可以通过"切碎"来显着改善这一点。搜索树

  1. RPN组合的负载在算术上是相同的(例如123456+++++ == 12345+6++++ == 1234+5+6+++等) - 您可以使用一些先验知识来改进generate_RPN_combinations,以便它不会生成它们
  2. 识别显示某些组合的中间结果可能永远不会满足您的标准,也不会在该道路上探索任何进一步的组合。
  3. 然后您必须将每个字符串发送到RPN计算器。这些是相当容易编码和典型的编程练习 - 您将值推送到堆栈上,当您来到运算符时,从堆栈中弹出前两个成员,应用运算符并将结果推送到堆栈。如果你不想实现它 - 谷歌minimal python rpn calculator,那里有资源可以帮助你。

    注意,您说您不必使用全部6个号码。我不建议单独实施,而是在评估所有6个数字的组合时建议检查任何中间结果,如果它们满足标准,也要保留它们。