【问题标题】:Expression from an array of numbers来自数字数组的表达式
【发布时间】:2012-11-05 11:00:01
【问题描述】:

给你三样东西

1) 一个由“n”个正整数和负整数组成的数组。 2) 数字“x”。 3) 运算符:'+'、'-'、'%'、'/'

用数组形成一个表达式,这样当你计算它时,结果会变成'x'。

例如,考虑数组 [5,3,-1,6,2,3] 和 x=2,一种可能的解决方案是

5 / 3 + (-1) + 6 / 2 - 1

假设 5 / 3 的结果是 1(总是整数除法)。

我有一个更复杂的变体。

在这个问题的复杂变体中,假设 BODMASS 规则不适用。因此,在任何时候,您都遍历了元素“m”,并且得到了中间结果“y”。您可以将任何运算符应用于 'y' 和 a[m + 1]。

例如,在变体 1 中,

5 + 3 - 2 / 2 = 7(首先计算 2 / 2,所以 5 + 3 - 1)

在变体 2 中,

5 + 3 - 2 / 2 = 3(5 + 3 = 8。数组减少到 8 - 2 / 2。现在,8 -2 = 6。数组减少到 6 / 2,计算结果为 3)。

算法/数学/DS 专家?

这是一个 NP 难吗?

【问题讨论】:

    标签: algorithm math data-structures np np-hard


    【解决方案1】:

    有 4 个运算符,因此一组 n 项有 4^(n-1) 个可能的值。您可以构建一个搜索空间图,其中每条路径代表一组运算符值,终点是计算的结果。

    在所有这些终点中,只有那些给出正确答案的终点才会在正确的终点结束。

    但请注意,如果从终点开始,则可以向后遍历;只有当您有一组有效的运算符时,您才会以第一个值结束。

    所以从两端遍历它,两个计算会在中间相遇。这是一个小得多的空间,每个方向 4^(n/2) = 2^n。为了匹配这两组答案,您需要对中间得到的列表进行排序,尽管您可能更愿意在每一步都这样做,以防止重复路径被遵循。此时看起来很像迷宫穿越。

    一个已知的 NP 完全问题是 Boolean satisfiability 的问题,它是“确定给定布尔公式的变量是否可以以使公式计算为 TRUE 的方式分配的问题”。我怀疑由于搜索空间明显大于布尔可满足性问题的空间,并且由于解决方案还将确定公式是可满足的(因此至少与解决可满足性一样难),那么问题应该是 NP 完全的。

    在迷宫的意义上,值偏离零的部分解不太可能是正确的解,并且给定参数的初始扫描,应该清楚对大小有什么限制(即所有乘法),这在布尔问题中不是这样。

    编辑:澄清我在开头提到的树。假设我们的列表是

     1 ? 2 ? 5 = X
    

    那么图形是这样的:

     r1 -->  r2  ---> r3 (X)
    
     1  +2    3  +5    8
                 -5   -2
                 *5   15
                 /5    0
    
        -2   -1  +5    4
                 -5   -6
                 *5   -5
                 /5    0
    
        *2    2  +5    7
                 -5   -3
                 *5   10
                 /5    0
    
        /2    0  +5    5
                 -5   -5
                 *5    0
                 /5    0
    

    如您所见,如果 X 为 -5,则它可能是 1 -2 *5 或 1 /2 -5。从 -5 向后工作:

    -5 +5    0
       -5  -10
       *5  -25
       /5   -1
    

    因此,如果我们从每一端开始,我们将位于中间一列,唯一的共同值将是 -1 和 0,从而产生具有 8 次计算的两条路径,而不是仅在一个方向上进行的 16 条路径。

    我错过的一点是整数除法不是 1:1 映射,因此向后退一步是模棱两可的; -4/5 -> 0, -3/5 -> 0 等等,直到 4/5 -> 0。0 是最坏的情况,因为它是从 0 的任一侧接近的,但即使是 20/10 到 29/10 也是如此映射到相同的值,2。这是一个相当大的障碍;它通过被除数的大小后退时增加可能节点的数量,因此对于 5,有 3+5 = 8 个可能的状态,而不是 4。

    【讨论】:

    • 是不是每个节点都有 4 * (n - 1) 条边?在这个图中,任何包含初始集合所有元素的路径都成为一个表达式?
    • 每条边都是对表达式中前一个值的操作,所以对于表达式 1 * 7 + 3,节点是 1, 7, 21,边 (*7) 和 (+3 )。我没有说得很清楚。因此,给定节点的 4 条出边是与下一个元素的 4 种可能操作,到达 4 个子节点。从 7 开始,有 +3、-3、*3 和 /3,到达节点 10、4、21、2。在树的每个等级上,它前面的路径都没有关系,因此您可以合并任何公共节点以减少正在进行的树大小。
    • 当你说with the next element 时没有(n - 1)个下一个元素吗?因为任何元素都可以使用任何操作与任何其他元素组合。在您的示例中给定 {1, 7, 3},从 7 开始,除了您已经提到的边缘之外,还可以有边 +1、-1、*1、/1。我喜欢这种方法,它非常优雅,试图更好地理解它。干杯!
    • 是的,我给出了单个路径中的节点示例,而不是整个树。我已经更新了答案以更清楚地显示示例树。我认为很明显,您实际上希望比较两个方向的值,并偏爱与另一方最匹配的值;如果反向步进已经达到某个较大的正数,则正向步进中较大的正节点最有可能产生解决方案。
    • @AsiriRathnayake:我明白你的意思,这会使问题变得更加困难,因为当排序不固定时,解决方案的数量是排列的。您可能需要为每个排序创建一个树...
    【解决方案2】:

    这是一个递归解决方案的尝试(对于简单版本):

    Gen {'x'} = {'x'}
    Gen {'x', 'y'} = {'x + y', 'x - y', 'y - x', 'x / y', 'y / x', 'x % y', 'y % x'}
    S0 = {a[0]}
    Gen S(i + 1) = {j ∈ S(i) | Gen {j, a[i + 1]}}
    

    最终答案是:∃ j ∈ S(n). x = [[ j ]]

    也就是说,我们逐步构建所有可能的(作为表达式),然后最终评估所有这些值,看看其中一个是否可以产生x(也可以逐步进行评估)。

    但是,在这里我假设a 中的值在构建表达式时是线性使用的。我意识到你的问题不是这种情况......

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-09-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多