divide a bunch of positive integers into 2 groups, requiring 2 groups and a minimum difference.
For example: 1 2 3 4 5, 1 2 4 are divided into 1 groups, 3 5 are divided into 1 groups, two groups and 1 difference, is the least difference in all scenarios. Integer number n<=100, all integers and <=10000
first of all, I think of greed. How greedy? Rank, each time put the number to the "most advantageous" side, the most advantageous point is each time puts the number to make the result difference value as small as possible that side. It is not right that the first two numbers can only be divided into different groups. For example, the greedy will separate 1 and 2, obviously without the optimal solution. The optimal solution is {3} together, in a group of one-on-each.
is it true that if you find a number equal to the other number, you must first open the number to the other few points? Because of this the spread value is still 0. No, look at {1,2,3,7}, we can't separate {3} from that. Instead, they should be put together in a group to be optimal.
It's not a trick. All-in-one enumeration ah, we put each number either put the first group, or put the second group, so altogether 2^n kind of situation, take a kind of difference value the smallest is good. This method is possible, but the actual complexity is too high.
continue the enumeration of ideas, why should we try so many cases? Since we are deciding which group to put the number of I in, the two groups of the preceding 2^i-1 may have different difference values. Right! The key factor is not in the previous 2^i-1, but in the case of the difference.
So, we use the bool F (I,J) to indicate that the first I number is divided into two groups, the difference is whether the case of J is possible. consider the meaning of F (i,j). We put the number of I in a certain group, the difference becomes J (J >= 0)
There are two possible groups in which the number of I is placed:
(1) The number of I into the original and larger group, then put the number of the time difference into J, pull the difference value, so the original difference is J-ai (J >=ai), then if F (i-1, J-ai) is true, then F (i,j) is true
(2) The number of I in the original and relatively small group, then put in the number of the first and then there are two cases:
(2.1) The original difference is very large, is already a J + AI, joined AI narrowed the gap, so that means if f (i-1, j + ai) = True, then f (i,j) is true.
(2.2) The original difference is not small, after the addition of AI, and the smaller group into a larger group. So the original larger than the small and big Ai–j (Ai >=j), so that means if f (i–1, ai–j) is true, then F (i,j) is true.
(1) and (2.2) can be unified into if f (i-1, |j-ai|) = True, then f (i,j) = True
summarize what I said earlier.
f (i,j) = f (i–1, |j-ai|) | | f (i–1, J + ai)
here we skillfully use absolute values and logic or operations.
continue to consider, what is the initial value? F (0,0) = True. When there are no numbers, the difference can only be 0, the remaining f (0,x > 0) = False.
How big is the second dimension? The second dimension can reach all numbers so the time complexity is O (n * sum), and the spatial complexity is O (n * sum), where sum is the sum of all the numbers.
What is the final answer?
by definition, the final answer is min{x| f (n,x) = true}
space optimization? F (I, *) is only related to f (i–1, *), so two lines, to achieve the purpose of recursion.
the solution above does not seem to be dynamic, because the dynamic programming equation should look like an "optimization" problem, that is, it should have Max or min, rather than a bool value. So, do we have another way?
Consider the final grouping situation, if all the sums are sum, the smaller and the group number must not exceed [SUM/2]. Our goal is to make it as large as the sum of the group.
Our goal is to select some numbers from the n number, the sum of which does not exceed [SUM/2] and the sum as large as possible.
then we redefine int f (I,J) to indicate the number of numbers selected in the previous I number, sum not exceeding J when the maximum can be obtained.
If you do not select Ai f (i-1,j) = f (i,j)
If AI is selected, f (i,j) = f (i, J-ai) J >= Ai
the second-dimensional size is [SUM/2]
The initial value is f (0, X) = 0 Note that the sum of "no more than" X is the maximum.
the recursive type is
F(I,J)= { f ( Span id= "MATHJAX-SPAN-17" class= "Mi" >i− 1, J) (j< ai ) /span> {MAX(F(I−1,J),F(I,J−AI)+ai ) Span id= "mathjax-span-60" class= "Mi" >ai <=j <=[ Sum/2]) Span id= "mathjax-span-75" class= "Mo" >
So what's the final answer? By definition, it should be f (n, [SUM/2]).
Time complexity and spatial complexity are still O (n * [SUM/2]), which can also optimize the spatial complexity of one dimension.
In summary, the time complexity of both methods are O (n * sum) level, usually sum is not very large, for example, the sum is not more than 10000, so from a practical point of view, the complexity is much stronger than O (2n).
Incidentally, what if we ask for a specific allocation scheme for the optimal solution?
don't forget, dynamic programming problems, the usual way to find a specific solution is to record the current F (i,j) is from the previous state, and then step by step carefully back to the starting point, as we recorded in the search problem before the node recovery path. The following:
#include <iostream>#include<bits/stdc++.h>using namespacestd; intd[11000],a[10100]; intMain () {intN; scanf ("%d",&N); intsum=0; for(intI=0; i<n;i++) {scanf ("%d",&A[i]); Sum+=A[i]; } intm=sum/2; memset (d,0,sizeof(d)); for(intI=0; i<n;i++) for(intj=m;j>=a[i];j--) D[j]=max (d[j],d[j-a[i]]+A[i]); cout<<sum-2*d[m]<<Endl; }
If it helps you, do not forget to add praise Oh, the clatter!! See you next time! the
Basic explanation of dynamic regulation eight--positive integer grouping