使用python,查找其和尽可能接近另一个的数字组合

使用python,查找其和尽可能接近另一个的数字组合,python,combinations,permutation,itertools,knapsack-problem,Python,Combinations,Permutation,Itertools,Knapsack Problem,问题是: 我需要在array2中找到三个加起来或尽可能接近array3中每个数字的数字(必须是三个数字) 打印列表1中array2中使用的每个数字的相应索引 只能使用数组2中的每个数字两次 数据:我在一个列表和两个数组中有三组数据。第一个列表是名称,第二个数组是数字,第三个数组是目标。列表1和数组2的长度相同(55),但不是数组3 list1 = ['ab', 'ac', 'ad', 'ae', 'af', 'ag', 'ah', 'ai', 'aj', 'ak', 'bc', 'bd', '

问题是:

  • 我需要在array2中找到三个加起来或尽可能接近array3中每个数字的数字(必须是三个数字)

  • 打印列表1中array2中使用的每个数字的相应索引

  • 只能使用数组2中的每个数字两次

  • 数据:我在一个列表和两个数组中有三组数据。第一个列表是名称,第二个数组是数字,第三个数组是目标。列表1和数组2的长度相同(55),但不是数组3

    list1 = ['ab', 'ac', 'ad', 'ae', 'af', 'ag', 'ah', 'ai', 'aj', 'ak', 
    'bc', 'bd', 'be', 'bf', 'bg', 'bh', 'bi', 'bj', 'bk', 'cd', 'ce', 
    'cf', 'cg', 'ch', 'ci', 'cj', 'ck', 'de', 'df', 'dg', 'dh', 'di', 
    'dj', 'dk', 'ef', 'eg', 'eh', 'ei', 'ej', 'ek', 'fg', 'fh', 'fi', 
    'fj', 'fk', 'gh', 'gi', 'gj', 'gk', 'hi', 'hj', 'hk', 'ij', 'ik', 
    'jk']
    array2 = [39, 6, 29, 38, 2, 34, 7, 6, 2, 3, 37, 13, 20, 18, 4, 14, 
    28, 2, 20, 25, 13, 38, 32, 28, 9, 7, 14, 11, 31, 29, 29, 39, 9, 35, 
    14, 34, 23, 31, 11, 2, 37, 19, 18, 6, 5, 12, 6, 33, 30, 22, 38, 37, 
    13, 31, 40]
    array3 = [80, 74, 84, 89, 89, 78, 79, 85, 81, 89, 75, 86, 76, 71, 
    82, 79, 75, 78, 83, 89]
    
    我期待的结果是:

    对于数组3中的80,使用39+38+3,即列表1中的“ab”、“ae”、“ak”

    对于数组3中的74,使用39+32+2,即列表1中的“ab”、“cg”、“ek”

    等等


    我正试图找到一种类似python的方法来解决这个问题,使用python3.x。我已经研究了itertools.组合/置换和背包问题。背包问题是最接近于解决这个问题的问题,但它评估了两个值以获得针对目标的最佳解决方案,我只需要一个。 我不是在找人帮我写代码(如果你想,我不会阻止你),而是在找一个比我更有经验的人来为我指出解决这个问题的正确方向。

    这假设array2中的每个元素(具有不同索引)只使用一次(可以扩展到元素重复),你不在乎使用哪三种元素:

    # target is the desired number from array3
    def triplet_sum(list1, array2, target):
        n = len(array2)
        a = [(i, array2[i]) for i in range(n)]
        a.sort(key=lambda x: x[1])
        j = 1
        i = j-1
        k = j+1
        best_sum = sys.maxsize
        best_answer = None
        while j < n:
            while i >= 0 and k < n:
                x = a[i][1]
                y = a[j][1]
                z = a[k][1]
                S = x + y + z
                candidate = [(x, list1[a[i][0]]), (y, list1[a[j][0]]), (z, list1[a[k][0]])]
                if S == target:
                    return candidate
                elif S > target:
                    i -= 1
                else:
                    k += 1
                if abs(target - best_sum) > abs(target - S):
                    best_sum = S
                    best_answer = candidate
            j += 1
            i = j-1
            k = j+1
        return best_answer
    

    我只是沿着排序列表
    a
    移动我的中间选择
    j
    ,如果
    S
    太高,总是用
    I
    向左移动,如果
    S
    太低,总是用
    k
    向右移动。O(n^2)复杂性一目了然。

    以下算法在
    array2
    中所有三元组的巨大空间中搜索e解,以查找
    array3
    中的所有目标:

    list1 = ['ab', 'ac', 'ad', 'ae', 'af', 'ag', 'ah', 'ai', 'aj', 'ak', 'bc', 'bd', 'be', 'bf', 'bg', 'bh', 'bi', 'bj', 'bk', 'cd', 'ce', 'cf', 'cg', 'ch', 'ci', 'cj', 'ck', 'de', 'df', 'dg', 'dh', 'di', 'dj', 'dk', 'ef', 'eg', 'eh', 'ei', 'ej', 'ek', 'fg', 'fh', 'fi', 'fj', 'fk', 'gh', 'gi', 'gj', 'gk', 'hi', 'hj', 'hk', 'ij', 'ik', 'jk']
    array2 = [39, 6, 29, 38, 2, 34, 7, 6, 2, 3, 37, 13, 20, 18, 4, 14, 28, 2, 20, 25, 13, 38, 32, 28, 9, 7, 14, 11, 31, 29, 29, 39, 9, 35, 14, 34, 23, 31, 11, 2, 37, 19, 18, 6, 5, 12, 6, 33, 30, 22, 38, 37, 13, 31, 40]
    array3 = [80, 74, 84, 89, 89, 78, 79, 85, 81, 89, 75, 86, 76, 71, 82, 79, 75, 78, 83, 89]
    
    import itertools
    import numpy as np
    import heapq
    import copy
    
    list1 = np.array(list1, dtype=str)
    array2 = np.array(array2, dtype=int)
    array3 = np.array(array3, dtype=int)
    
    m, n = len(array2), len(array3)
    
    combs = [[] for __ in range(n)]
    
    maxuses = 2
    
    combinations = set(map(tuple, itertools.combinations(list(range(m))*maxuses, 3)))
    print(f'searching in {len(combinations)}! space')
    
    def dist(a, b):
        return abs(a - b)
    
    for i, target in enumerate(array3):
        for comb in map(list, combinations):
            combs[i].append((dist(target, sum(array2[comb])), comb))
    
        combs[i].sort(key=lambda item: item[0])
    
    tested = set()
    
    cost = 0
    locs = [0]*n
    used = {i: [] for i in range(m)}
    
    for i in range(n):
        for value in combs[i][0][1]:
            used[value].append(i)
        cost += combs[i][0][0]
    
    def priority(values):
        return (np.array(list(map(len, values)))**2).sum()
    
    minheap = [(cost, priority(used.values()), locs, used)]
    
    count = 0
    while minheap:
        cost, __, locs, used = heapq.heappop(minheap)
    
        count += 1
        print(f'tested {count}, best cost {cost}, heap size {len(minheap)}')
    
        for key in used:
            if len(used[key]) > maxuses:
                loc1 = used[key][-1]
                loc2 = next(itertools.islice(filter(lambda x: x != loc1, used[key]), 0, None))
    
                print(f'value at {key} is used by {len(used[key])} combinations')
    
                # print(key, used[key])
                # print(loc1, combs[loc1][locs[loc1]][1])
                # print(loc2, combs[loc2][locs[loc2]][1])
                for value in combs[loc1][locs[loc1]][1]:
                    used[value].remove(loc1)
                for value in combs[loc2][locs[loc2]][1]:
                    used[value].remove(loc2)
    
                if loc1 < len(combinations)-1:
                    cost1 = cost
                    locs1 = list(locs)
                    used1 = copy.deepcopy(used)
    
                    cost1 -= combs[loc1][locs[loc1]][0]
                    locs1[loc1] += 1
                    cost1 += combs[loc1][locs[loc1]][0]
    
                    for value in combs[loc1][locs1[loc1]][1]:
                        used1[value].append(loc1)
                    for value in combs[loc2][locs1[loc2]][1]:
                        used1[value].append(loc2)
    
                    if tuple(locs1) not in tested:
                        tested.add(tuple(locs1))
                        heapq.heappush(minheap, (cost1, priority(used1.values()), locs1, used1))
    
                if loc2 < len(combinations)-1:
                    cost2 = cost
                    locs2 = list(locs)
                    used2 = copy.deepcopy(used)
    
                    cost2 -= combs[loc2][locs2[loc2]][0]
                    locs2[loc2] += 1
                    cost2 += combs[loc2][locs2[loc2]][0]
    
                    for value in combs[loc1][locs2[loc1]][1]:
                        used2[value].append(loc1)
                    for value in combs[loc2][locs2[loc2]][1]:
                        used2[value].append(loc2)
    
                    if tuple(locs2) not in tested:
                        tested.add(tuple(locs2))
                        heapq.heappush(minheap, (cost2, priority(used2.values()), locs2, used2))
                break
        else:
            print(f'found a solution with {cost} cost:')
            print(locs)
    
            for i , target in enumerate(array3):
                print(f'{target}\t~=\t ', end='')
                print(*array2[combs[i][locs[i]][1]], sep='+', end=' ')
                print('\t(', end='')
                print(*list1[combs[i][locs[i]][1]], sep=', ', end='')
                print(')')
    
            exit()
    

    “我正试图找到一种类似蟒蛇的方法来解决这个问题”乍一看,这个问题可能小到足以在合理的时间内使用暴力(我还没有计算出复杂性)。再大一点;算了吧,你已经开始尝试启发式了。有尺寸限制吗?如果您不担心将计数扩展到100以上,那么这是非常容易的。否则,这是一个算法问题。到目前为止,你尝试了什么?给我们看一些代码!一个
    array2
    编号可以为每个
    array3
    编号使用两次,还是总共使用两次?后者更为复杂。@davishering
    array2
    number每个
    array3
    只能使用一次,总的来说只能使用两次@RockyLi不幸的是,
    array3
    中的计数可能超过100,但我对你如何解决这个问题感兴趣@美元。我弄乱了背包函数,但遇到的问题是它需要一个
    和一个
    权重
    。我试着修改它,只使用上面提到的其中一个,但它就是不起作用。这让我觉得我处理这个问题的方法是错误的,所以我在这里向你们这些聪明的人请教如何解决这个问题。
    list1 = ['ab', 'ac', 'ad', 'ae', 'af', 'ag', 'ah', 'ai', 'aj', 'ak', 'bc', 'bd', 'be', 'bf', 'bg', 'bh', 'bi', 'bj', 'bk', 'cd', 'ce', 'cf', 'cg', 'ch', 'ci', 'cj', 'ck', 'de', 'df', 'dg', 'dh', 'di', 'dj', 'dk', 'ef', 'eg', 'eh', 'ei', 'ej', 'ek', 'fg', 'fh', 'fi', 'fj', 'fk', 'gh', 'gi', 'gj', 'gk', 'hi', 'hj', 'hk', 'ij', 'ik', 'jk']
    array2 = [39, 6, 29, 38, 2, 34, 7, 6, 2, 3, 37, 13, 20, 18, 4, 14, 28, 2, 20, 25, 13, 38, 32, 28, 9, 7, 14, 11, 31, 29, 29, 39, 9, 35, 14, 34, 23, 31, 11, 2, 37, 19, 18, 6, 5, 12, 6, 33, 30, 22, 38, 37, 13, 31, 40]
    array3 = [80, 74, 84, 89, 89, 78, 79, 85, 81, 89, 75, 86, 76, 71, 82, 79, 75, 78, 83, 89]
    
    import itertools
    import numpy as np
    import heapq
    import copy
    
    list1 = np.array(list1, dtype=str)
    array2 = np.array(array2, dtype=int)
    array3 = np.array(array3, dtype=int)
    
    m, n = len(array2), len(array3)
    
    combs = [[] for __ in range(n)]
    
    maxuses = 2
    
    combinations = set(map(tuple, itertools.combinations(list(range(m))*maxuses, 3)))
    print(f'searching in {len(combinations)}! space')
    
    def dist(a, b):
        return abs(a - b)
    
    for i, target in enumerate(array3):
        for comb in map(list, combinations):
            combs[i].append((dist(target, sum(array2[comb])), comb))
    
        combs[i].sort(key=lambda item: item[0])
    
    tested = set()
    
    cost = 0
    locs = [0]*n
    used = {i: [] for i in range(m)}
    
    for i in range(n):
        for value in combs[i][0][1]:
            used[value].append(i)
        cost += combs[i][0][0]
    
    def priority(values):
        return (np.array(list(map(len, values)))**2).sum()
    
    minheap = [(cost, priority(used.values()), locs, used)]
    
    count = 0
    while minheap:
        cost, __, locs, used = heapq.heappop(minheap)
    
        count += 1
        print(f'tested {count}, best cost {cost}, heap size {len(minheap)}')
    
        for key in used:
            if len(used[key]) > maxuses:
                loc1 = used[key][-1]
                loc2 = next(itertools.islice(filter(lambda x: x != loc1, used[key]), 0, None))
    
                print(f'value at {key} is used by {len(used[key])} combinations')
    
                # print(key, used[key])
                # print(loc1, combs[loc1][locs[loc1]][1])
                # print(loc2, combs[loc2][locs[loc2]][1])
                for value in combs[loc1][locs[loc1]][1]:
                    used[value].remove(loc1)
                for value in combs[loc2][locs[loc2]][1]:
                    used[value].remove(loc2)
    
                if loc1 < len(combinations)-1:
                    cost1 = cost
                    locs1 = list(locs)
                    used1 = copy.deepcopy(used)
    
                    cost1 -= combs[loc1][locs[loc1]][0]
                    locs1[loc1] += 1
                    cost1 += combs[loc1][locs[loc1]][0]
    
                    for value in combs[loc1][locs1[loc1]][1]:
                        used1[value].append(loc1)
                    for value in combs[loc2][locs1[loc2]][1]:
                        used1[value].append(loc2)
    
                    if tuple(locs1) not in tested:
                        tested.add(tuple(locs1))
                        heapq.heappush(minheap, (cost1, priority(used1.values()), locs1, used1))
    
                if loc2 < len(combinations)-1:
                    cost2 = cost
                    locs2 = list(locs)
                    used2 = copy.deepcopy(used)
    
                    cost2 -= combs[loc2][locs2[loc2]][0]
                    locs2[loc2] += 1
                    cost2 += combs[loc2][locs2[loc2]][0]
    
                    for value in combs[loc1][locs2[loc1]][1]:
                        used2[value].append(loc1)
                    for value in combs[loc2][locs2[loc2]][1]:
                        used2[value].append(loc2)
    
                    if tuple(locs2) not in tested:
                        tested.add(tuple(locs2))
                        heapq.heappush(minheap, (cost2, priority(used2.values()), locs2, used2))
                break
        else:
            print(f'found a solution with {cost} cost:')
            print(locs)
    
            for i , target in enumerate(array3):
                print(f'{target}\t~=\t ', end='')
                print(*array2[combs[i][locs[i]][1]], sep='+', end=' ')
                print('\t(', end='')
                print(*list1[combs[i][locs[i]][1]], sep=', ', end='')
                print(')')
    
            exit()
    
    80      ~=       28+23+29       (ch, eh, dg)
    74      ~=       29+39+6        (dg, di, ai)
    84      ~=       13+33+38       (ij, gj, hj)
    89      ~=       37+39+13       (bc, di, ij)
    89      ~=       30+40+19       (gk, jk, fh)
    78      ~=       7+40+31        (ah, jk, ei)
    79      ~=       31+18+30       (ei, fi, gk)
    85      ~=       13+37+35       (ce, fg, dk)
    81      ~=       18+32+31       (bf, cg, df)
    89      ~=       34+20+35       (eg, be, dk)
    75      ~=       13+28+34       (bd, bi, ag)
    86      ~=       18+39+29       (bf, ab, dh)
    76      ~=       29+38+9        (ad, hj, dj)
    71      ~=       14+37+20       (bh, bc, be)
    82      ~=       29+20+33       (dh, bk, gj)
    79      ~=       14+37+28       (ef, hk, ch)
    75      ~=       28+9+38        (bi, ci, ae)
    78      ~=       34+38+6        (eg, cf, gi)
    83      ~=       29+31+23       (ad, df, eh)
    89      ~=       37+38+14       (hk, cf, ef)