我很困惑如何制作一个算法来查找列表中元素的组合,其中这些因子的总和是最低的,其中这些数字的因子是预定的目标值。
例如一个清单:
(2,5,7,6,8,2,3)
目标值:
12
会导致这些因素:
(2,2,3) and (2,6)
但最佳组合是:
(2,2,3)
因为它的总和
答案 0 :(得分:2)
首先从列表中删除所有不是n
因子的数字。因此,在您的示例中,您的列表将减少为(2, 6, 2, 3)
。然后我会对列表进行排序。所以你有(2, 2, 3, 6)
。如果达到n停止,则开始将元素从左向右相乘。如果你超过n,找到你的数字的下一个最小的排列并重复。这将是(2, 2, 6, 3)
(对于找到下一个排列的C ++函数,请参阅this link)。这将保证找到最小和的乘法因为我们按照从最小总和到最大的顺序检查产品。这会以你的列表阶乘的大小运行,但我认为这与你将获得的一样好。这个问题听起来很难。
你可以通过修剪排列来做得更好。让我们说你正在寻找24,你的清单是(2,4,8,12)。唯一的子集是(2,12)。但是下一个排列将是(2,4,12,8)你甚至不需要生成,因为你知道2 * 4太小而2 * 4 * 8太大而交换12只8只增加2 * 4 * 8。这样你就不必测试那种排列。
答案 1 :(得分:1)
您应该能够以递归方式解决问题。您有多个潜在因素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_i
。时间的复杂性可能很糟糕,但你没有说明你在这方面的目标是什么。
答案 2 :(得分:1)
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
答案 3 :(得分:0)
以下是你在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 <- subsequences xs, product x == target]
构建一个列表,该列表由列表xs
的所有子序列组成,其产品等于target
。在您的示例中,它将构建列表[[2,6],[6,2],[2,2,3]]
。
然后sortBy (compare
sum)
部分按列表元素的总和对该列表列表进行排序。它将返回列表[[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) => [b] -> b -> [b]
部分只是函数的类型签名。这意味着该函数采用由b
s组成的列表,第二个参数b
并返回由b
组成的另一个列表,b
是Ord
的成员{1}}完全有序的数据类型类,Num
类,基本数字类。
Obs3:我还是初学者。一个更有经验的程序员可能会更有效和更优雅地做到这一点。