簡體   English   中英

給定一個范圍列表,找到這些范圍的所有組合,總和為 k

[英]Given a list of ranges, find all combination for these ranges that sums upto k

我有 34 個數字范圍。 例如:

x1 = {25,35}
x2 = {28,36}
x3 = {15,20}
.
.
x34 = {28,37}

我必須找到所有組合,以便我從每個范圍中選擇一個數字,並且所有這 34 個數字總和為 k。

例如:

let k = 600

so from x1 - we pick 26

from x2 - we pick 29

.

.

and from x34 we pick 16.

Then, x1 + x2 + x3 + x4 + … + x34 = 600.

我想要所有這樣的組合。

用某種算法可行嗎?

我想在 python 中實現這個。

range(a, b) a 包括在內, b 不包括在內。 所以這里的實際范圍是:

{20, 25}
{30, 36}
{10, 39}
all_ranges = [range(20, 26), range(30, 37), range(10, 40)]

def get_combinations(ranges, k):
    if ranges.__len__() == 0:
        return int(k == 0)

    combinations = 0
    for i in ranges[0]:
#        if k - i < 0:
#            break
        combinations += get_combinations(ranges[1:], k - i)
    return combinations

print(get_combinations(all_ranges, 70))

我們不會將數字相加直到達到k ,而是從k中減去直到達到零。

if ranges.__len__() == 0:
    return int(k == 0)

這是終止遞歸的塊。 基本上,如果我們從k中減去從范圍中選擇的每個數字,那么結果必須為零。

combinations = 0
for i in ranges[0]:
    combinations += get_combinations(ranges[1:], k - i)

請注意,注釋的部分僅用於提高效率。 所以我們在這里選擇一個數字,我們最初選擇它是k 然后我們遍歷第一個范圍的所有值,並獲得新的k - i與新的范圍ranges[1:]的組合。 你可以看到這些東西是如何結合在一起的。

編輯並更正答案

請原諒我,我沒有注意到 OP 本身需要這些組合。 盡管如此,我還是將上面的代碼留給未來的訪問者。

使用與上述相同的邏輯,我們可以得到二維列表中的所有組合。

from copy import deepcopy
all_ranges = [range(20, 26), range(30, 37), range(10, 40)]

def get_combinations(ranges, k, initial_combination=None):
    if not initial_combination:
        initial_combination = []
    combinations = []
    if ranges.__len__() == 1:
        for i in ranges[0]:
            if k - i < 0:
                return combinations
            elif k - i == 0:
                _ = deepcopy(initial_combination)
                _.append(i)
                combinations.append(_)
        return combinations

    for i in ranges[0]:
        _ = deepcopy(initial_combination)
        _.append(i)
        combinations += get_combinations(ranges[1:], k - i, _)
    return combinations

get_combinations(all_ranges, 70)

注意: 深拷貝功能

計算效率 HACK

from copy import deepcopy
all_ranges = [range(10, 40), range(20, 30), range(40, 50)]


def get_minimums():
    m = []
    for index, r in enumerate(all_ranges):
        m.append(sum([_.start for _ in all_ranges[index + 1:]]))

minimums = get_minimums() #[60, 40, 0]


def get_combinations(ranges, k, initial_combination=None):
    if not initial_combination:
        initial_combination = []
    combinations = []
    if ranges.__len__() == 1:
        for i in ranges[0]:
            if k - i < 0:
                break
            elif k - i == 0:
                _ = deepcopy(initial_combination)
                _.append(i)
                print(_)
                combinations.append(_)

        return combinations

    minimum = minimums[-ranges.__len__()]
    for i in range(ranges[0].start, ranges[0].stop):
        if k - minimum - i < 0:
            break

        _ = deepcopy(initial_combination)
        _.append(i)
        combinations += get_combinations(ranges[1:], k - i, _)
    return combinations

get_combinations(all_ranges, 90)

您可以使用 itertools 的產品方法來檢查 n 個 arrays 之間的所有組合。

例如:

import itertools
a = [1,2]
b = ['a' , 'b']
c = list(itertools.product(a,b))
>> [(1, 'a'), (1, 'b'), (2, 'a'), (2, 'b')]

因此,如果您想知道構成給定數字的所有組合,您只需在最終列表中進行迭代並檢查所有結果。

import itertools

x1 = range(25,35)
x2 = range(28,36)
x3 = range(15,20)

result = []
for item in list(itertools.product(x1,x2,x3)):
    if sum(item) == 75:
        result.append(item)

print(result)
>> [(25, 31, 19), (25, 32, 18), (25, 33, 17), (25, 34, 16), .....]

如果您以前不知道范圍數,您只需在 itertools.product 中使用 * 運算符,代碼將相同

ranges = [range(1,5), range(5,29), range(3, 400), ...]

#STUFF

itertools.product(*ranges)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM