【问题标题】:Given list of digits, keep digits in order while using +-*/ to get specific result给定数字列表,在使用 +-*/ 时保持数字顺序以获得特定结果
【发布时间】:2011-10-01 00:00:44
【问题描述】:

不确定以前是否有人问过这个问题,但找不到此类问题的具体提及。

这是子集和和背包的变体。

虽然有类似的问题appears to have been asked before,但逻辑不同,足以保证一个新线程。

参数: 给出了总数以及整数列表。 整数可以以多种方式组合(例如 1 2 3 = 12、3 或 1、23 或 1、2 3) 允许 3 次操作:

  • 1 次添加
  • 1 减法
  • 1 个部门

示例:

1 2 9 3 7 4 = 22

解决方案:

(129 - 3) / 7 + 4 = 22

这种运动有分类吗? (例如子集和等)

一些想法:

  1. 创建一个包含所有可能数字组合的多维数组。 由于只允许使用 3 个运算符,因此该数组将包含 3 个列/元素。

  2. 在点 1、2 或 3 处随机插入运算符并进行暴力破解,直到找到解决方案。

这与优雅的解决方案相去甚远。
任何见解将不胜感激。

我可能会在 Perl 中编写此代码,但任何语言的伪代码、指针或语法都会很棒。傲慢地嘲笑我缺乏数学能力也很酷;)

提前致谢!

【问题讨论】:

标签: algorithm perl pseudocode


【解决方案1】:

我刚刚回答了这个问题,但它被错误地迁移到另一个 stackexchange 站点:https://codegolf.stackexchange.com/questions/3019/getting-an-answer-from-a-string-of-digits/3027#3027

这种运动有分类吗? (例如子集和等)

我称之为查找列表的所有二元运算符“减少”,以任意顺序应用,运算符 +、-、*、/ 和 10a+b/@ 987654329@


这是 python 中的一种蛮力方法。在下面树中的每个节点处,取左右可能性的笛卡尔积。对于每一对,将所有运算符应用于它,以产生一组新的可能性。你要小心不要做(1-2)3 = -13;您可以通过创建 Digit 对象来解决此问题。

下面是加泰罗尼亚数字的说明,其中每个节点都是一个运算符。操作数大约为Catalan(#digits-1) * #operators^(#digits-1)。如果#digits=10,那么它应该只有大约十亿次尝试。

使用How to print all possible balanced parentheses for an expression?我们可以写:

#!/usr/bin/python3

import operator as op
from fractions import Fraction
Fraction.__repr__ = lambda self: '{}/{}'.format(self.numerator, self.denominator)

Digits = tuple

operators = {op.add, op.sub, op.mul, Fraction}

def digitsToNumber(digits):
    """
        (1,2,3) -> 123
        123 -> 123
    """
    if isinstance(digits, Digits):
        return sum(d * 10**i for i,d in enumerate(reversed(digits)))
    else: # is int or float
        return digits

def applyOperatorsToPossibilities(left, right):
    """
        Takes every possibility from the left, and every
        possibility from the right, and takes the Cartesian
        product. For every element in the Cartesian product,
        applies all allowed operators.

        Returns new set of merged possibilities, ignoring duplicates.
    """
    R = set() # subresults
    def accumulate(n):
        if digitsToNumber(n)==TO_FIND:
            raise Exception(n)
        else:
            R.add(n)

    for l in left:
        for r in right:
            if isinstance(l, Digits) and isinstance(r, Digits):
                # (1,2),(3) --> (1,2,3)
                accumulate(l+r)
            for op in operators:
                #  12,3 --> 12+3,12-3,12*3,12/3
                l = digitsToNumber(l)
                r = digitsToNumber(r)
                try:
                    accumulate(op(l,r))
                except ZeroDivisionError:
                    pass

    return R

def allReductions(digits):
    """
        allReductions([1,2,3,4])
        [-22, -5, -4, -3, -5/2, -1/1, -1/3, 0, 1/23, 1/6, 1/5, 1/3, 2/3, 1/1, 3/2, 5/3, 2, 7/2, 4/1, 5, 6, 7, 9, 15, 23, 24, 36, 123]
    """
    for reduction in set.union(*associations(
            digits, 
            grouper=applyOperatorsToPossibilities, 
            lifter=lambda x:{(x,)})
            ):
        yield digitsToNumber(reduction)

TO_FIND = None
INPUT = list(range(1,4))
print(sorted(allReductions(INPUT)))

【讨论】:

  • 谢谢!非常感谢。今天晚些时候将尝试针对此特定场景实施和重写。
【解决方案2】:

一种简单的蛮力方法,似乎效果很好。

让我们使用RPN 来避免括号。将输入拆分为单个数字并尝试在数字之间插入运算符(即:无、空格和算术运算符),直到结果字符串计算为目标值。

javascript 插图:http://jsfiddle.net/B5NdN/4。我只是简单地从 0 循环到 6^(输入长度​​)以获得那里所有可能的运算符组合,您的任务可能需要更复杂的东西,但原则仍然存在。

【讨论】:

  • 非常值得深思,非常感谢。没想到/不熟悉 RPN。
猜你喜欢
  • 2020-08-31
  • 1970-01-01
  • 2023-03-04
  • 2015-12-09
  • 1970-01-01
  • 2021-12-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多