【问题标题】:Is partitioning an array into halves with equal sums P or NP?是否将数组分成两半,总和 P 或 NP 相等?
【发布时间】:2016-07-19 01:51:26
【问题描述】:

这是一道关于分区问题的算法面试题。

给你一个数组,包含 包含 0 到 5 位数字的数字。 编写一个函数,返回数组是否可以分割 分成两半,这样的总和 两半是相等的。

这是一个NP问题还是可以通过动态规划来解决?

“0 到 5 位之间”我认为是 0 ~ 99999。


我在 SO here 之外找到了一个很好的答案。

【问题讨论】:

  • 两半必须是连续的吗?还是只是一些任意分区?
  • @Gumbo♦ 我认为它可以是任意的

标签: algorithm complexity-theory dynamic-programming


【解决方案1】:

这显然是 NP - 可以在多项式时间内验证解决方案。

但是它不是 NP 完全的,因为元素是有界的(0 到 5 位范围之间的数字)。

已知问题会经历“相变”,对于 m / n

【讨论】:

    【解决方案2】:

    面试题的设计不仅是为了测试问题的解决能力,也是为了分析问题。所以这个问题不够具体。

    我可以选择任意两个元素子集,或者它们必须是一致的部分吗? 在第一种情况下,问题是 NP-Complete(有关更多信息,请参阅 http://en.wikipedia.org/wiki/Partition_problem),在第二种情况下,它当然是微不足道的(面试问题通常以微不足道的编程任务结束)。

    如果一般问题是 NP-Complete,也许我们可以尝试专门化它?我们对数组了解多少? 也许我们可以通过一些外部假设来简化问题?

    我认为这是处理此类问题的方式,也是面试官所希望的。

    更新:对于指定的数字范围,该问题相当于离散背包问题(背包的大小限制为整个数组和大小为 100000 的权重集合之和的一半,也就是说,我们可以解决它准时) 有关背包问题的更多信息,请参阅http://en.wikipedia.org/wiki/Knapsack_problem

    【讨论】:

      【解决方案3】:

      两者兼而有之。问题在于 NP,我很确定它可以通过动态规划在伪多项式时间内解决。

      http://en.wikipedia.org/wiki/Partition_problem

      一般问题是 NP 完全的,可以通过动态规划在伪多项式时间内求解。 T

      这种对 0-5 位数字的特定限制可能不是 NP 完全的。到底什么是 0 位数字?

      通常对于分区问题,不要求分区大小相等,只要它们具有相等的总和即可。但是这里你说“分为 2 个一半”,我不确定“一半”是指数组的一半,还是仅仅表示总数的一半。

      我猜这种差异,如果是差异的话,可能不会影响 DP 解决方案的复杂性,但我不确定。除了“嗯,是的,看起来像你可以用 DP 做的那种事情,我必须考虑一下”之外,我没有任何一种直接的证据。

      【讨论】:

      • 0 到 5 位的范围我认为是 0 到 99999。
      【解决方案4】:

      没错,如果集合的数量是有界的,那么问题就是多项式复杂度。

      您可以使用 bin 搜索技术。

      阅读 Partition_Problem 的 wikipage,然后,在开始时,您会发现对 Subset_Sum_Problem 的引用,它几乎是等价的。 您还应该找到有意义的阅读该 wiki 页面

      【讨论】:

        【解决方案5】:

        你可以使这个算法适应分区问题,不需要很多修改。

        求解和子集NP-完全问题的线性算法纯Python实现

        https://github.com/maxtuno/Universal/blob/master/linear_sum_subset_algorithm_oscar_riveros.py

        #!/usr/bin/env python3
        
        __author__ = "O. A. Riveros"
        __copyright__ = "Copyright 2014, O. A. Riveros, All right reserved"
        __license__ = "MIT"
        __email__ = "oscar.riveros@gmail.com"
        
        """
        O. A. Riveros
        http://independent.academia.edu/oarr
        http://twitter.com/maxtuno
        """
        
        """
        first 100 primes
        """
        data = [2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,281,283,293,307,311,313,317,331,337,347,349,353,359,367,373,379,383,389,397,401,409,419,421,431,433,439,443,449,457,461,463,467,479,487,491,499,503,509,521,523,541]
        
        solution = [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]
        
        """
        for custom entertainment
        solution = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
        """
        
        target = sum([data[i] for i in range(len(solution)) if solution[i] == 1])
        
        l = len(data)
        
        size = len('{0:b}'.format(sum(data)))
        
        def rotate(l,n):
            return l[n:] + l[:n]
        
        def slice(l, n):
            return list(int(l[i:i+n], 2) for i in range(0, len(l), n))
        
        data_second_order = []
        for i in range(l):
            data_second_order += rotate(data, i)
        
        T = 0
        for i in range(l):
            T += int(''.join('{0:b}'.format(k).zfill(size) for k in rotate(data_second_order, i)), 2)
            t = slice('{0:b}'.format(T).zfill(size*(l**2)), size)
            if (target in t):
                '''
                for review the results
                print('The target {} found in {} steps from {}.'.format(target, i + 1, t))
                '''
                print('The target {} found in {} steps'.format(target, i + 1))
                break
        
        """
        The target 24133 found in 100 steps
        """
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2015-12-19
          • 1970-01-01
          • 2019-07-24
          • 1970-01-01
          • 2022-06-10
          • 1970-01-01
          • 2021-03-01
          • 1970-01-01
          相关资源
          最近更新 更多