Python子集和

Python子集和,python,subset-sum,Python,Subset Sum,我正在尝试编写一个函数,该函数不仅可以确定集合子集的和是否会添加到所需的目标数,还可以打印作为解决方案的子集 以下是查找子集是否存在的代码: def subsetsum(array,num): if num == 0 or num < 1: return False elif len(array) == 0: return False else: if array[0] == num: ret

我正在尝试编写一个函数,该函数不仅可以确定集合子集的和是否会添加到所需的目标数,还可以打印作为解决方案的子集

以下是查找子集是否存在的代码:

def subsetsum(array,num):

    if num == 0 or num < 1:
        return False
    elif len(array) == 0:
        return False
    else:
        if array[0] == num:
            return True
        else:
            return subsetsum(array[1:],(num - array[0])) or subsetsum(array[1:],num)
def subsetsum(数组,num):
如果num==0或num<1:
返回错误
elif len(数组)==0:
返回错误
其他:
如果数组[0]==num:
返回真值
其他:
返回子序列(数组[1:],(num-array[0])或子序列(数组[1:],num)

我如何修改它来记录子集本身,以便打印它?提前谢谢

您可以改变您的方法,以便更轻松地做到这一点,例如:

def subsetsum(array, num):
    if sum(array) == num:
        return array
    if len(array) > 1:
        for subset in (array[:-1], array[1:]):
            result = subsetsum(subset, num)
            if result is not None:
                return result

这将根据您的解决方案返回有效子集或
None

def subsetsum(array,num):

    if num == 0 or num < 1:
        return None
    elif len(array) == 0:
        return None
    else:
        if array[0] == num:
            return [array[0]]
        else:
            with_v = subsetsum(array[1:],(num - array[0])) 
            if with_v:
                return [array[0]] + with_v
            else:
                return subsetsum(array[1:],num)
def subsetsum(数组,num):
如果num==0或num<1:
一无所获
elif len(数组)==0:
一无所获
其他:
如果数组[0]==num:
返回[数组[0]]
其他:
使用_v=subsetsum(数组[1:],(num-array[0]))
如果使用_v:
返回[array[0]]+,带_v
其他:
返回子序列(数组[1:],num)

我想我会在混合物中加入另一种解决方案

我们可以将列表子集的每个选择映射到一个(0填充的)二进制数,其中0表示不接受列表中相应位置的成员,1表示接受它

因此,用
0101
屏蔽
[1,2,3,4]
将创建子列表
[2,4]

因此,通过生成0到2^LENGTH\u范围内的所有0填充二进制数,我们可以迭代所有选择。如果我们使用这些子列表选择作为遮罩并对选择进行求和,我们就可以知道答案

这是如何做到的:

#!/usr/bin/env python

# use a binary number (represented as string) as a mask
def mask(lst, m):
    # pad number to create a valid selection mask 
    # according to definition in the solution laid out 
    m = m.zfill(len(lst))
    return map(lambda x: x[0], filter(lambda x: x[1] != '0', zip(lst, m)))

def subset_sum(lst, target):
    # there are 2^n binary numbers with length of the original list
    for i in xrange(2**len(lst)):
        # create the pick corresponsing to current number
        pick = mask(lst, bin(i)[2:])
        if sum(pick) == target:
            return pick
    return False


print subset_sum([1,2,3,4,5], 7)
输出:

[3, 4]
[[3, 4], [2, 5], [1, 2, 4]]
要返回所有可能性,我们可以使用生成器(唯一的更改是在
子集_sum
中,使用
收益率
而不是
返回
并删除
返回假
保护):

输出:

[3, 4]
[[3, 4], [2, 5], [1, 2, 4]]

注意:在不使用零填充掩码的情况下也可以使用,因为它只会以相反的顺序选择原始列表的成员-我没有选中它,也没有使用它


我没有使用它,因为它(对我来说)不太明显(1、0或什么都没有),我宁愿把所有东西都定义清楚。

稍微修改了萨米答案的版本,以打印所有可能的组合

def subset(array, num):
    result = []
    def find(arr, num, path=()):
        if not arr:
            return
        if arr[0] == num:
            result.append(path + (arr[0],))
        else:
            find(arr[1:], num - arr[0], path + (arr[0],))
            find(arr[1:], num, path)
    find(array, num)
    return result

通过递归打印所有子集的方法稍有不同

def subsetSumToK(arr,k):
    if len(arr)==0:
        if k == 0:
            return [[]]
        else:
            return []
    
    output=[]
    if arr[0]<=k: 
        temp2=subsetSumToK(arr[1:],k-arr[0])  #Including the current element 
        if len(temp2)>0:
            for i in range(len(temp2)):
                temp2[i].insert(0,arr[0])
                output.append(temp2[i])
    
    temp1=subsetSumToK(arr[1:],k)            #Excluding the current element
    if len(temp1)>0:
        for i in range(len(temp1)):
            output.append(temp1[i])
    return output

arr=[int(i) for i in input().split()]
k=int(input())
sub=subsetSumToK(arr,k)
for i in sub:
    for j in range(len(i)):
        if j==len(i)-1:
            print(i[j])
        else:
            print(i[j],end=" ")
def子系统正常(arr,k):
如果len(arr)==0:
如果k==0:
返回[]]
其他:
返回[]
输出=[]
如果arr[0]0:
对于范围内的i(len(temp2)):
temp2[i]。插入(0,arr[0])
output.append(temp2[i])
temp1=子TSUMTOK(arr[1:],k)#不包括当前元素
如果len(temp1)>0:
对于范围内的i(len(temp1)):
output.append(temp1[i])
返回输出
arr=[int(i)表示输入中的i().split()]
k=int(输入()
sub=SUBSTSUMTOK(arr,k)
对于我在sub:
对于范围内的j(len(i)):
如果j==len(i)-1:
打印(i[j])
其他:
打印(i[j],end=”“)

您可以使用迭代方法,而不是使用递归

def desiredSum(array, sum):

  numberOfItems = len(array)
  storage = [[0 for x in range(sum + 1)] for x in range(numberOfItems + 1)]

  for i in range(numberOfItems + 1):
    for j in range(sum + 1):

        value = array[i - 1]

        if i is 0: storage[i][j] = 0
        if j is 0: storage[i][j] = 1

        if value <= j:

            noTake = storage[i - 1][j]
            take = storage[i - 1][j - value]
            storage[i][j] = noTake + take

  return storage[numberOfItems][sum]
def desiredSum(数组,和):
numberOfItems=len(数组)
存储=[[0代表范围内的x(总和+1)]代表范围内的x(numberOfItems+1)]
对于范围内的i(numberOfItems+1):
对于范围内的j(总和+1):
值=数组[i-1]
如果i为0:storage[i][j]=0
如果j为0:storage[i][j]=1

if值返回子集的元组,以及总和是否添加到所需的目标数。类似于
返回子集,True
。不确定如何执行该操作。如何获取元组?您是否尝试在web上搜索如何获取元组。对不起,我知道如何返回多个值。这不是问题所在。我想知道如何将相加到所需数字的值添加到列表或元组中。现在该函数只确定True或False。我需要用值填充元组。你需要先自己做一些小努力@用户2872761 oops,输入错误;修正了这部作品。然而,我不能把我的头绕在for循环上。对这种特定的python语法有多少解释?在一个特定的迭代中,它的值是什么(子集和两个切片)?它是否在每次迭代中遍历每个子集值和两个数组(切片)?我问这个问题是因为我正在尝试将解决方案转换为PHP。为什么不输入一些
打印
并找出答案呢?@ArnabDatta这段代码只处理连续的子集,你必须稍微修改它以处理非连续的子集。我试过你的代码,但它在像subsetsum([2,5,3,4,6],7)这样的数组中效果不好,它返回[5,2],但是它也应该返回[3,4]。
num==0或num<1
会从冗余部门得到一个警告!这不适用于[1,3,4,5,6]和目标9。它只返回[1,3,5]