简体   繁体   English

我怎样才能减少子集和问题的时间复杂度

[英]how can i reduce the time complexity of subset sum problem

So lately I have been trying to solve some interesting problems,, but got quite stuck on this one.所以最近我一直在尝试解决一些有趣的问题,但在这个问题上陷入了困境。

Given a set of objects 1 to N. n1 objects with value 0 and n2 objects with value 1 and n3 objects with value 2. Need to count all the subsets with sum 3 or its multiple.给定一组对象 1 到 N。n1 个值为 0 的对象和 n2 个值为 1 的对象和 n3 个值为 2 的对象。需要计算总和为 3 或其倍数的所有子集。

n1+ n2 + n3 = N <= 100000 the value of n1, n2 and n3 can be 0 as well, while fulfilling the above condition. n1+ n2 + n3 = N <= 100000 在满足上述条件的情况下,n1、n2、n3的值也可以为0。

I have been able to solve the problem but not able to bring down the time complexity of this problem.我已经能够解决问题,但无法降低这个问题的时间复杂度。 My solution still has exponential time complexity.我的解决方案仍然具有指数时间复杂度。 I am trying to bring the time complexity down so that I can run for large set with N = 100,000 under 5 secs.我试图降低时间复杂度,以便我可以在 5 秒内运行 N = 100,000 的大型集合。

This is another simple but intutive solution I stumpled on but again time complexity is the problem.这是我偶然发现的另一个简单但直观的解决方案,但问题又是时间复杂度。

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 range(2**len(last)):
        # create the pick corresponsing to current number
        pick = mask(lst, bin(i)[2:])
        if sum(pick) == target:
            yield pick

I don't need the exact coded solutions, but would be great if you can point me in the right direction and any programming language would be okay, I would like to know the logic/approach of the solution.我不需要确切的编码解决方案,但如果你能指出正确的方向并且任何编程语言都可以,那就太好了,我想知道解决方案的逻辑/方法。

It seems like, given an array of numbers (all of which are 0, 1 or 2), you want to return every subset of these numbers that sum to a multiple of 3, and you want to do it polynomially.看起来,给定一个数字数组(所有数字均为 0、1 或 2),您想要返回这些数字的每个子集,这些数字总和为 3 的倍数,并且您希望以多项式的方式进行。

This is impossible.这是不可能的。

To see this, consider the array [2,1,0,0,0,0,0,...,0].要看到这一点,请考虑数组 [2,1,0,0,0,0,0,...,0]。 To get to a sum of 3 we will always require the first two numbers, but apart from that any subset sums to 3. As we have N-2 0s, that gives a total amount of 2**(N-2) subsets that fit the requirement.为了得到 3 的总和,我们将始终需要前两个数字,但除此之外,任何子集总和为 3。因为我们有N-2 0,所以总共有2**(N-2)个子集符合要求。 Returning an exponential amount of answers cannot be done in polynomial time.无法在多项式时间内返回指数数量的答案。

So a key knowledge here is that the sum must be a multiple of 3, that is sum = 0 (mod 3).所以这里的一个关键知识就是和必须是3的倍数,即sum = 0 (mod 3)。

This means you can include as many or as few of n1 as you want in any subset as they don't change the sum.这意味着您可以在任何子集中包含尽可能多或尽可能少的 n1,因为它们不会改变总和。

So you can immediately reduce the problem to finding subsets from n2 and n3 that sum to 0 (mod 3) and then add on all possible 2**n1 subsets to these.因此,您可以立即将问题简化为从 n2 和 n3 中找到总和为 0 (mod 3) 的子集,然后将所有可能的 2**n1 个子集添加到这些子集。 Note that for any signicant value of n1 (like above 50) this becomes uncomputable to list them.请注意,对于 n1 的任何显着值(如 50 以上),列出它们变得无法计算。

It is however easy to count:但是很容易计算:

So how to go about finding the sets from n2 and n3 that have sum = 0 (mod 3).那么 go 如何从 n2 和 n3 中找到 sum = 0 (mod 3) 的集合。 We know that any element from n2 increases the sum by one, given m elements from n2 we can calculate how many elements are possible from我们知道 n2 中的任何元素都会使总和增加 1,给定 n2 中的 m 个元素,我们可以计算出有多少个元素是可能的

so a loose pseudo code for counting:所以一个用于计数的松散伪代码:

def f(n1,n2,n3):
    for i in range(0,n2+1):
        # i elements of n2
        # compute i%3
        # if i%3 0 then we can pick j = 0,3,6,9 ... elements from n3
        # if i%3 1 then we can pick j = 1,4,7,10 .. elements from n3
        # if i#3 2 then we cannot j = 2, 5, 8, 11 .. elements from n3
        # compute the combination c = (n choose i) * (n choose j) for each j
        # for each c multiply by 2**n1 (adding on all possible subsets from n1)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM