【问题标题】:Represent natural number as sum of distinct squares将自然数表示为不同平方和
【发布时间】:2014-10-06 18:43:15
【问题描述】:

问题是找到最大的正整数集合 S,使得 S 的元素的平方和等于给定数 n。

例如:

4 = 2²
20 = 4² + 2²
38 = 5² + 3² + 2²
300 = 11² + 8² + 7² + 6² + 4² + 3² + 2² + 1²。

我有一个及时运行的算法O(2^(sqrt n) * n),但它太慢了(每个正方形子集)。

【问题讨论】:

  • 所以问题是你追求更快的算法?
  • 很遗憾我的解决方案太慢了。
  • 你的问题并不清楚,因为你根本没有提到它。
  • 你给出的例子是错误的。 300 可以写成 11² + 8² + 7² + 6² + 4² + 3² + 2² + 1²。
  • OP,你熟悉动态规划吗?您可以在任何优秀的算法书籍中了解它。

标签: algorithm number-theory


【解决方案1】:

有一个基于subset sum 的规范动态程序的O(n^1.5)-time 算法。这是重复的:

C(m, k) is the size of the largest subset of 1..k whose squares sum to m
C(m, k), m < 0 = -infinity (infeasible)
C(0, k) = 0
C(m, 0), m > 0 = -infinity (infeasible)
C(m, k), m > 0, k > 0 = max(C(m, k-1), C(m - k^2, k-1) + 1)

0..n 中的所有m0..floor(n^0.5) 中的所有k 计算C(m, k)。返回 C(n, floor(n^0.5)) 作为目标值。要恢复集合,请回溯 argmax。

【讨论】:

    【解决方案2】:

    我只是想知道这个问题是否可以简化为 NP?看起来您的整数(平方)列表小于n(可以在O(sqrt(n)) 中生成),并且您正在寻找来自1 to sqrt(n) 的子集总和(检查所有可能性)。如果是这样,它应该可以通过O(n^2) 中的背包动态规划算法(但这是一种非常幼稚的算法,我认为可以改进)来解决 - sqrt(n) 检查次数 sqrt(n) 背包物品计数次数 n 背包重量。

    编辑: 我认为在填充动态编程数组后使用智能回溯,您可以在 O(n*sqrt(n)) 中完成。

    【讨论】:

      【解决方案3】:

      你可以使用循环:

      T(0, m) = 0
      T(n, m) = -Infinity (if n<0 or m<0)
      T(n, m) = max(T(n-m*m, m-1)+1, T(n, m-1))
      

      或者,在 Python 代码中:

      from functools import lru_cache
      
      @lru_cache(100000)
      def T(n, m):
          if n<0 or m<0: return (-1000000, 0)
          if n==0: return (0, 0)
          return max((T(n-m*m, m-1)[0]+1, m), T(n, m-1)) 
      
      def squares(n):
          s = int(n**0.5)
          while n>0 and s>0:
              _, factor = T(n, s)
              yield factor**2
              n -= factor**2
              s = factor-1
      
      for x in (4, 20, 38, 300):
          result = list(squares(x))
          print(sum(result), '= sum', result) 
      

      你给出的例子(300),可以用8个因素写成:

      300 = 11² + 8² + 7² + 6² + 4² + 3² + 2² + 1²

      其他结果:

      4 = sum [4]
      20 = sum [16, 4]
      38 = sum [25, 9, 4]
      300 = sum [121, 64, 49, 36, 16, 9, 4, 1]
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-10-22
        • 1970-01-01
        • 1970-01-01
        • 2011-03-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-05-30
        相关资源
        最近更新 更多