Getting the lowest possible sum from numbers' difference

后端 未结 10 1321
滥情空心
滥情空心 2020-12-23 22:19

I have to find the lowest possible sum from numbers\' difference.

Let\'s say I have 4 numbers. 1515, 1520, 1500 and 1535. The lowest sum of difference is 30, becaus

10条回答
  •  南方客
    南方客 (楼主)
    2020-12-23 22:40

    The solution by marcog is a correct, non-recursive, polynomial-time solution to the problem — it's a pretty standard DP problem — but, just for completeness, here's a proof that it works, and actual code for the problem. [@marcog: Feel free to copy any part of this answer into your own if you wish; I'll then delete this.]

    Proof

    Let the list be x1, …, xN. Assume wlog that the list is sorted. We're trying to find K (disjoint) pairs of elements from the list, such that the sum of their differences is minimised.

    Claim: An optimal solution always consists of the differences of consecutive elements.
    Proof: Suppose you fix the subset of elements whose differences are taken. Then by the proof given by Jonas Kölker, the optimal solution for just this subset consists of differences of consecutive elements from the list. Now suppose there is a solution corresponding to a subset that does not comprise pairs of consecutive elements, i.e. the solution involves a difference xj-xi where j>i+1. Then, we can replace xj with xi+1 to get a smaller difference, since
    xi ≤ xi+1 ≤ xj ⇒ xi+1-xi ≤ xj-xi.
    (Needless to say, if xi+1=xj, then taking xi+1 is indistinguishable from taking xj.) This proves the claim.

    The rest is just routine dynamic programming stuff: the optimal solution using k pairs from the first n elements either doesn't use the nth element at all (in which case it's just the optimal solution using k pairs from the first n-1), or it uses the nth element in which case it's the difference xn-xn-1 plus the optimal solution using k-1 pairs from the first n-2.

    The whole program runs in time O(N log N + NK), as marcog says. (Sorting + DP.)

    Code

    Here's a complete program. I was lazy with initializing arrays and wrote Python code using dicts; this is a small log(N) factor over using actual arrays.

    '''
    The minimum possible sum|x_i - x_j| using K pairs (2K numbers) from N numbers
    '''
    import sys
    def ints(): return [int(s) for s in sys.stdin.readline().split()]
    
    N, K = ints()
    num = sorted(ints())
    
    best = {} #best[(k,n)] = minimum sum using k pairs out of 0 to n
    def b(k,n):
        if best.has_key((k,n)): return best[(k,n)]
        if k==0: return 0
        return float('inf')
    
    for n in range(1,N):
        for k in range(1,K+1):
            best[(k,n)] = min([b(k,n-1),                      #Not using num[n]
                               b(k-1,n-2) + num[n]-num[n-1]]) #Using num[n]
    
    print best[(K,N-1)]
    

    Test it:

    Input
    4 2
    1515 1520 1500 1535
    Output
    30
    
    Input
    8 3
    1731 1572 2041 1561 1682 1572 1609 1731
    Output
    48
    

提交回复
热议问题