【问题标题】:Select a number from two sets each that the sum of their multiplication equals to a specific sum从两组中选择一个数字,每组的乘积之和等于特定的总和
【发布时间】:2018-04-19 22:34:56
【问题描述】:

我有两个集合,例如 A={0,1,2,...,i} 和 B={3,6,10,15},一个常量 $s$ 和一个指定数字 $n$属于自然数集。 我想找到满足 a_1*b_1+a_2*b_2+\dots+a_n*b_n>=s

的 a/所有组合

例如,如果 s=25, n=2 以下每个答案都是可接受的 1*10+1*15 , 2*10+1*6 , 0+2*15 或 4*3+2*6

如果我没有第二组,那会很容易,因为问题减少到产生具有预定 sum 的随机分区,如 here 中介绍的那样

我应该如何在 python 中有效地实现这一点?有什么数学方法可以做到吗? 它也让我想起了某种方程式,但我不确定我应该搜索什么。 我很感激任何提示。

编辑:对我来说,在我的答案中准确包含“n”个术语很重要,并且还有其他选择的机会。在我的示例中,四个答案中的每一个都应该有生成的机会。换句话说,我有“n”个地方用我的术语填充它们,使得它们的总和等于“s”。很抱歉没有一开始就清除它。

【问题讨论】:

    标签: python pandas numpy random


    【解决方案1】:

    这可以通过直接递归来完成。

    from functools import lru_cache
    
    def find_combinations(numbers, threshold, nterms, maxcoeff, stringify=True):
        numbers = sorted(numbers, reverse=True)
        @lru_cache(None)
        def rec(k, s, n):
            if s > maxcoeff * numbers[k]:
                top = maxcoeff
                res = []
            else:
                top = (s-1) // numbers[k]
                res = [[top + 1]]
            if n > 1 and k < len(numbers)-1:
                for j in range(top, -1, -1):
                    res.extend([[j, *subres] for subres in rec(
                        k+1, s-j*numbers[k], n-(j!=0))])
            return res
        if stringify:
            return [' + '.join(f'{c}\u2a2f{n}' for c, n in zip(sol, numbers) if c)
                    for sol in rec(0, threshold, nterms)]
        else:
            return rec(0, threshold, nterms)
    
    print(find_combinations({3, 6, 10, 15}, 25, 2, 2))
    

    打印:

    ['2⨯15', '1⨯15 + 1⨯10', '2⨯10 + 1⨯6']
    

    更新:允许numbers出现多次(这些都集中在一起,基本上是maxcoeff乘以每个数字的出现次数):

    def find_combinations_with_replacement(numbers, threshold, nterms, maxcoeff,
                                           stringify=True):
        numbers = sorted(numbers, reverse=True)
        @lru_cache(None)
        def rec(k, s, n):
            if s > maxcoeff * numbers[k] * n:
                return []
            top = (s-1) // numbers[k]
            res = [[top + 1]]
            if n > 1 and k < len(numbers)-1:
                for j in range(top, -1, -1):
                    res.extend([[j, *subres] for subres in rec(
                        k+1, s-j*numbers[k], n - (j-1) // maxcoeff - 1)])
            return res
        if stringify:
            return [' + '.join(f'{c}\u2a2f{n}' for c, n in zip(sol, numbers) if c)
                    for sol in rec(0, threshold, nterms)]
        else:
            return rec(0, threshold, nterms)
    
    print(find_combinations_with_replacement({3, 6, 10, 15}, 25, 4, 1))
    

    打印:

    ['2⨯15', '1⨯15 + 1⨯10', '1⨯15 + 2⨯6', '1⨯15 + 1⨯6 + 2⨯3', '3⨯10', '2⨯10 + 1⨯6', '2⨯10 + 2⨯3', '1⨯10 + 3⨯6', '1⨯10 + 2⨯6 + 1⨯3']
    

    【讨论】:

    • 非常感谢。如果我用“find_combinations({3, 6, 10, 15}, 25, 4,1,True)" 调用它,它总是返回我 ['1⨯15 + 1⨯10'] 但 ['1⨯3+1 ⨯3+1⨯3+3⨯6'] 和 ['0⨯3+2⨯3+1⨯3+3⨯6'] 也是一种可能的解决方案。我需要有机会(均匀分布)来生成它们,而不仅仅是一种可能的解决方案。我认为“maxcoeff”可以防止它。我该怎么做呢?我在我的问题中添加了更多信息。再次感谢
    • @roadstorm 啊,我假设B 的元素可能只出现一次。 maxcoeffi 相同。 (这里我假设A 的形式总是0, 1, 2, 3, ..., i)。
    • 谢谢,但我的输出仍有问题。当我设置 n=9 和 s=25 时,我无法得到 $['1⨯3+1⨯3+1⨯3+1⨯3+1⨯3+1⨯3+1⨯3+1⨯3 这样的答案+1⨯3']$。 “maxcoeff”是一个非常方便的变量来限制“i”。让总和正好等于 s 怎么样,是否有助于减少可行空间?谢谢
    • @roadstorm 为了使输出更短一些,这些被归为一个术语9x3。可以在第二步中扩展它,但它会加速组合爆炸。
    • 也许我们应该在解决方案选择中添加某种随机性,以便在每次运行算法时生成不同的答案?编辑:我会看一下以了解您的最后评论。谢谢
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-08
    • 2021-12-29
    • 1970-01-01
    • 2017-02-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多