首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何在分区算法中检索子集?

如何在分区算法中检索子集?
EN

Stack Overflow用户
提问于 2016-09-15 15:23:33
回答 2查看 126关注 0票数 4

我有一个数组,我想把它分成两个部分,这样它们的和是相等的,例如,[10, 30, 20, 50]可以被拆分为[10, 40] , [20, 30]。两者的总和都是50。这本质上是分区算法,但我希望检索子集,而不仅仅是识别它是否可以分区。于是,我做了以下几件事:

更新:处理重复项的更新脚本

代码语言:javascript
复制
from collections import Counter

def is_partitionable(a):
    possible_sums = [a[0]]
    corresponding_subsets = [[a[0]]]
    target_value = sum(a)/2
    if a[0] == target_value:
        print("yes",[a[0]],a[1:])
        return
    for x in a[1:]:
        temp_possible_sums = []
        for (ind, t) in enumerate(possible_sums):
            cursum = t + x
            if cursum < target_value:
                corresponding_subsets.append(corresponding_subsets[ind] + [x])
                temp_possible_sums.append(cursum)
            if cursum == target_value:
                one_subset = corresponding_subsets[ind] + [x]
                another_subset = list((Counter(a) - Counter(one_subset)).elements())
                print("yes", one_subset,another_subset)
                return
        possible_sums.extend(temp_possible_sums)
    print("no")
    return

is_partitionable(list(map(int, input().split())))

样本输入和输出:

代码语言:javascript
复制
>>> is_partitionable([10,30,20,40])
yes [10, 40] [30, 20]
>>> is_partitionable([10,30,20,20])
yes [10, 30] [20, 20]
>>> is_partitionable([10,30,20,10])
no

实际上,我存储的是为在corresponding_subsets中获取值而添加的相应值。但是,随着a大小的增加,很明显,corresponding_subsets会有太多的子列表(等于possible_sums中的元素数)。是否有更好/更有效的方法来做到这一点?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2016-09-15 16:08:30

虽然这仍然是一个困难的问题,但您可以尝试以下方法。我假设有n元素,它们存储在名为arr的数组中(我假设基于1的索引)。让我们让两个团队AB,这样我想在团队AB之间划分arr的元素,这样两个团队中的元素之和是相等的。arr的每个元素都可以选择使用team A或team B。假设一个元素(例如ith元素)进入team A,我们用-a[i]来表示它,如果它去team B,则让它成为a[i]。因此,在将每个元素分配给一个团队之后,如果总金额为0,那么我们的工作就完成了。我们将创建n集(它们不存储副本)。我将使用示例arr = {10,20,30,40}。按照以下步骤执行

代码语言:javascript
复制
set_1 = {10,-10} # -10 if it goes to Team A and 10 if goes to B

set_2 = {30,-10,10,-30} # four options as we add -20 and 20

set_3 = {60,0,20,-40,-20,-60} # note we don't need to store duplicates

set_4 = {100,20,40,-40,60,-20,-80,0,-60,-100} # see there is a zero means our task is possible

现在,您所要做的就是从最后一组的0中回溯,看看ith元素a[i]是以a[i]还是-a[i]的形式添加的。无论是添加到Team A还是B中。

编辑

回溯程序。所以我们有n集,从set_1set_n。让我们创建两个列表list_A来推送属于team A和类似的list_B的元素。我们从set_n开始,因此使用变量current_set最初具有值n。此外,我们将重点放在最后一个列表中的元素0上,从而使用变量current_element最初具有值0。按照下面代码中的方法(我假设所有的集合1到n已经形成,为了方便起见,我已经将它们存储为列表列表,但是您应该使用set数据结构)。另外,下面的代码假设在最后一个列表中看到了一个0,即。我们的任务是可能的。

代码语言:javascript
复制
sets = [ [0], #see this dummy set it is important, this is set_0
              #because initially we add -arr[0] or arr[0] to 0
         [10,-10],
         [30,-10,10,-30],
         [60,0,20,-40,-20,-60],
         [100,20,40,-40,60,-20,-80,0,-60,-100]]

# my array is 1 based so ignore the zero
arr = [0,10,20,30,40]

list_A = []
list_B = []

current_element = 0
current_set = 4 # Total number of sets in this case is n=4

while current_set >= 1:
   print current_set,current_element
   for element in sets[current_set-1]:
     if element + arr[current_set] == current_element:
       list_B.append(arr[current_set])
       current_element = element
       current_set -= 1
       break
     elif element - arr[current_set] == current_element:
       list_A.append(arr[current_set])
       current_element = element
       current_set -= 1
       break


print list_A,list_B
票数 3
EN

Stack Overflow用户

发布于 2016-09-15 16:39:05

这是我实现@sasha's algo的可行性。

代码语言:javascript
复制
def my_part(my_list):
    item = my_list.pop()
    balance = []
    temp = [item, -item]
    while len(my_list) != 0:
        new_player = my_list.pop()
        for i, items in enumerate(temp):
            balance.append(items + new_player)
            balance.append(items - new_player)
        temp = balance[:]
    balance = set(balance)
    if 0 in balance:
        return 'YES'
    else:
        return 'NO'

我也在做回溯。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/39514839

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档