N-fold partition of an array with equal sum in each partition

后端 未结 3 821
一整个雨季
一整个雨季 2021-01-19 08:22

Given an array of integers a, two numbers N and M, return N group of integers from a such that each group su

相关标签:
3条回答
  • 2021-01-19 09:01

    Here is my own Python solution that uses dynamic programming. The algorithm is given here.

    def get_subset(lst, s):
        '''Given a list of integer `lst` and an integer s, returns
        a subset of lst that sums to s, as well as lst minus that subset
        '''
        q = {}
        for i in range(len(lst)):
            for j in range(1, s+1):
                if lst[i] == j:
                    q[(i, j)] = (True, [j])
                elif i >= 1 and q[(i-1, j)][0]:
                    q[(i, j)] = (True, q[(i-1, j)][1])
                elif i >= 1 and j >= lst[i] and q[(i-1, j-lst[i])][0]:
                    q[(i, j)] = (True, q[(i-1, j-lst[i])][1] + [lst[i]])
                else:
                    q[(i, j)] = (False, [])
    
            if q[(i, s)][0]:
                for k in q[(i, s)][1]:
                    lst.remove(k)
    
                return q[(i, s)][1], lst
    
        return None, lst
    
    def get_n_subset(n, lst, s):
        ''' Returns n subsets of lst, each of which sums to s'''
        solutions = []
        for i in range(n):
            sol, lst = get_subset(lst, s)
            solutions.append(sol)
    
        return solutions, lst
    
    
    # print(get_n_subset(7, [1, 2, 3, 4, 5, 7, 8, 4, 1, 2, 3, 1, 1, 1, 2], 5))
    # [stdout]: ([[2, 3], [1, 4], [5], [4, 1], [2, 3], [1, 1, 1, 2], None], [7, 8])
    
    0 讨论(0)
  • 2021-01-19 09:02

    People give up too easily on NP-complete problems. Just because a problem is NP complete doesn't mean that there aren't more and less efficient algorithms in the general case. That is you can't guarantee that for all inputs there is an answer that can be computed faster than a brute force search, but for many problems you can certainly have methods that are faster than the full search for most inputs.

    For this problem there are certainly 'perverse' sets of numbers that will result in worst case search times, because there may be say a large vector of integers, but only one solution and you have to end up trying a very large number of combinations.

    But for non-perverse sets, there are probably many solutions, and an efficient way of 'tripping over' a good partitioning will run much faster than NP time.

    How you solve this will depend a lot on what you expect to be the more common parameters. It also makes a difference if the integers are all positive, or if negatives are allowed.

    In this case I'll assume that:

    1. N is small relative to the length of the vector
    2. All integers are positive.
    3. Integers cannot be re-used.

    Algorithm:

    1. Sort the vector, v.
    2. Eliminate elements bigger than M. They can't be part of any solution.
    3. Add up all remaining numbers in v, divide by N. If the result is smaller than M, there is no solution.
    4. Create a new array w, same size as v. For each w[i], sum all the numbers in v[i+1 - end]

    So if v was 5 4 3 2 1, w would be 10, 6, 3, 1, 0.

    While you have not found enough sets:

    1. Chose the largest number, x, if it is equal to M, emit a solution set with just x, and remove it from the vector, remove the first element from w.

    Still not enough sets? (likely), then again while you have not found enough sets:

    1. A solution theory is ([a,b,c], R ) where [a,b,c] is a partial set of elements of v and a remainder R. R = M-sum[a,b,c]. Extending a theory is adding a number to the partial set, and subtracting that number from R. As you extend the theories, if R == 0, that is a possible solution.

    Recursively create theories like so: loop over the elements v, as v[i] creating theories, ( [v[i]], R ), And now recursively extend extend each theory from just part of v. Binary search into v to find the first element equal to or smaller than R, v[j]. Start with v[j] and extend each theory with the elements of v from j until R > w[k].

    The numbers from v[j] to v[k] are the only numbers that be used to extend a theory and still get R to 0. Numbers larger than v[j] will make R negative. Smaller larger than v[k], and there aren't any more numbers left in the array, even if you used them all to get R to 0

    0 讨论(0)
  • 2021-01-19 09:08

    this appears to be a variation of the subset sum problem. as this problem is np-complete, there will be no efficient algorithm without further constraints.

    note that it is already hard to find a single subset of the original set whose elements would sum up to M.

    0 讨论(0)
提交回复
热议问题