Fast solution to Subset sum

后端 未结 6 1442
不思量自难忘°
不思量自难忘° 2020-11-27 19:09

Consider this way of solving the Subset sum problem:

def subset_summing_to_zero (activities):
  subsets = {0: []}
  for (activity, cost) in activities.iterit         


        
6条回答
  •  情歌与酒
    2020-11-27 19:47

    I respect the alacrity with which you're trying to solve this problem! Unfortunately, you're trying to solve a problem that's NP-complete, meaning that any further improvement that breaks the polynomial time barrier will prove that P = NP.

    The implementation you pulled from Hacker News appears to be consistent with the pseudo-polytime dynamic programming solution, where any additional improvements must, by definition, progress the state of current research into this problem and all of its algorithmic isoforms. In other words: while a constant speedup is possible, you're very unlikely to see an algorithmic improvement to this solution to the problem in the context of this thread.

    However, you can use an approximate algorithm if you require a polytime solution with a tolerable degree of error. In pseudocode blatantly stolen from Wikipedia, this would be:

    initialize a list S to contain one element 0.
     for each i from 1 to N do
       let T be a list consisting of xi + y, for all y in S
       let U be the union of T and S
       sort U
       make S empty 
       let y be the smallest element of U 
       add y to S 
       for each element z of U in increasing order do
          //trim the list by eliminating numbers close to one another
          //and throw out elements greater than s
         if y + cs/N < z ≤ s, set y = z and add z to S 
     if S contains a number between (1 − c)s and s, output yes, otherwise no
    

    Python implementation, preserving the original terms as closely as possible:

    from bisect import bisect
    
    def ssum(X,c,s):
        """ Simple impl. of the polytime approximate subset sum algorithm 
        Returns True if the subset exists within our given error; False otherwise 
        """
        S = [0]
        N = len(X)
        for xi in X:
            T = [xi + y for y in S]
            U = set().union(T,S)
            U = sorted(U) # Coercion to list
            S = []
            y = U[0]
            S.append(y)
            for z in U: 
                if y + (c*s)/N < z and z <= s:
                    y = z
                    S.append(z)
        if not c: # For zero error, check equivalence
            return S[bisect(S,s)-1] == s
        return bisect(S,(1-c)*s) != bisect(S,s)
    

    ... where X is your bag of terms, c is your precision (between 0 and 1), and s is the target sum.

    For more details, see the Wikipedia article.

    (Additional reference, further reading on CSTheory.SE)

提交回复
热议问题