【问题标题】:Finding the lowest sum of values in a list to form a target factor查找列表中值的最小总和以形成目标因子
【发布时间】:2015-06-29 04:43:10
【问题描述】:

我不知道如何制定一种算法来从列表中找到元素组合,其中这些因素的总和尽可能低,而这些数字的因素是预定的目标值。

例如一个列表:

(2,5,7,6,8,2,3)

还有一个目标值:

12

会导致这些因素:

(2,2,3) and (2,6)

但最佳组合是:

(2,2,3)

因为它的总和较低

【问题讨论】:

  • 这听起来像是欧拉问题:)
  • 欧拉问题?只是一些背景,我试图在数学游戏中最大化我的分数。
  • 是的,欧拉问题是一个数学游戏。你应该检查一下。
  • 您需要处理多大的列表?您必须处理多大的目标值?

标签: algorithm sum


【解决方案1】:

首先从列表中删除所有不是n 因数的数字。因此,在您的示例中,您的列表将减少到 (2, 6, 2, 3)。然后我会对列表进行排序。所以你有(2, 2, 3, 6)。如果到达 n 停止,则开始从左到右将元素相乘。如果你超过 n 找到你的数字的下一个最小排列并重复。这将是 (2, 2, 6, 3)(对于找到下一个排列的 C++ 函数,请参阅 this link)。这将保证找到总和最小的乘法,因为我们正在按从最小和到最大的顺序检查乘积。这以您的列表阶乘的大小运行,但我认为这与您将获得的一样好。这个问题听起来 NP 很难。

您可以通过修剪排列做得更好。假设您正在寻找 24,而您的列表是 (2, 4, 8, 12)。唯一的子集是 (2, 12)。但是下一个排列将是 (2, 4, 12, 8),您甚至不需要生成它,因为您知道 2*4 太小而 2*4*8 太大并且将 12 与 8 交换只会增加2*4*8。这样您就不必测试该排列。

【讨论】:

  • 经过大量时间研究和阅读您的见解后,我想出了一种递归方式来做到这一点,我将把它作为答案
【解决方案2】:

您应该能够递归地分解问题。您有多个潜在因素S = {n_1, n_2, ..., n_k}。令f(S,n) 为最大和n_i_1 + n_i_2 + ... + n_i_j,其中n_i_l 是多重集的不同元素,n_i_1 * ... * n_i_j = n。然后f(S,n) = max_i { (n_i + f(S-{n_i},n/n_i)) where n_i divides n }。换句话说,f(S,n) 可以递归计算。再做一点工作,您就可以让算法吐出实际有效的n_is。时间复杂度可能很差,但您没有说明您在这方面的目标是什么。

【讨论】:

    【解决方案3】:
    def primes(n):
        primfac = []
        d = 2
        while d*d <= n:
            while (n % d) == 0:
                primfac.append(d)  # supposing you want multiple factors repeated
                n //= d
            d += 1
        if n > 1:
           primfac.append(n)
        return primfac
    
    def get_factors_list(dividend, ceiling = float('infinity')):
        """ Yield all lists of factors where the largest is no larger than ceiling """
        for divisor in range(min(ceiling, dividend - 1), 1, -1):
            quotient, mod = divmod(dividend, divisor)
            if mod == 0:
                if quotient <= divisor:
                    yield [divisor, quotient]
                for factors in get_factors_list(quotient, divisor):
                    yield [divisor] + factors
    
    def print_factors(x):
        factorList = []
        if x > 0:
            for factors in get_factors_list(x):
                factorList.append(list(map(int, factors)))
        return factorList
    

    【讨论】:

      【解决方案4】:

      这是在 Haskell 中如何做到的:

      import Data.List(sortBy, subsequences)
      import Data.Function(on)
      
      lowestSumTargetFactor :: (Ord b, Num b) => [b] -> b -> [b]
      lowestSumTargetFactor xs target = do
          let l =  filter (/= []) $ sortBy (compare `on` sum) 
                  [x | x <- subsequences xs, product x == target]
          if l == []
              then error $ "lowestSumTargetFactor: " ++ 
                  "no subsequence product equals target."
              else head l
      

      这是发生了什么:

      [x | x &lt;- subsequences xs, product x == target] 构建一个由列表xs 的所有子序列组成的列表,其乘积等于target。在您的示例中,它将构建列表[[2,6],[6,2],[2,2,3]]

      然后sortBy (compareonsum) 部分按列表元素的总和对该列表列表进行排序。它将返回列表[[2,2,3],[2,6],[6,2]]

      然后我 filter 该列表,删除任何 [] 元素,因为 product [] 返回 1(还不知道这样做的原因)。这样做是因为 lowestSumTargetFactor [1, 1, 1] 1 将返回 [] 而不是预期的 [1]

      然后我问我们建立的列表是否是[]。如果不是,我使用函数head 返回该列表的第一个元素(在您的情况下为[2,2,3])。如果是,则返回所写的错误。

      Obs1:在上面出现的地方,$ 只是表示它后面的所有内容都用括号括起来。

      Obs2:lowestSumTargetFactor :: (Ord b, Num b) =&gt; [b] -&gt; b -&gt; [b] 部分只是函数的类型签名。这意味着该函数接受一个由bs 组成的列表,第二个参数b 并返回另一个由bs 组成的列表,b 是完全有序数据类型Ord 类的成员,和Num 类,基本的数字类。

      Obs3:我还是个初学者。更有经验的程序员可能会更高效、更优雅地完成此操作。

      【讨论】:

        猜你喜欢
        • 2016-04-20
        • 1970-01-01
        • 2018-08-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-09-19
        • 2021-03-19
        相关资源
        最近更新 更多