How to divide a set into two subsets such that difference between the sum of numbers in two sets is minimal?

前端 未结 18 709
攒了一身酷
攒了一身酷 2020-11-27 10:55

Given a set of numbers, divide the numbers into two subsets such that difference between the sum of numbers in two subsets is minimal.

T

18条回答
  •  死守一世寂寞
    2020-11-27 11:50

    No, Your algorithm is wrong. Your algo follows a greedy approach. I implemented your approach and it failed over this test case: (You may try here)

    A greedy algorithm:

    #include
    #define rep(i,_n) for(int i=0;i<_n;i++)
    using namespace std;
    
    #define MXN 55
    int a[MXN];
    
    int main() {
        //code
        int t,n,c;
        cin>>t;
        while(t--){
            cin>>n;
            rep(i,n) cin>>a[i];
            sort(a, a+n);
            reverse(a, a+n);
            ll sum1 = 0, sum2 = 0;
            rep(i,n){
                cout<

    Test case:

    1
    8 
    16 14 13 13 12 10 9 3
    
    Wrong Ans: 6
    16 13 10 9
    14 13 12 3
    
    Correct Ans: 0
    16 13 13 3
    14 12 10 9
    

    The reason greedy algorithm fails is that it does not consider cases when taking a larger element in current larger sum set and later a much smaller in the larger sum set may result much better results. It always try to minimize current difference without exploring or knowing further possibilities, while in a correct solution you might include an element in a larger set and include a much smaller element later to compensate this difference, same as in above test case.

    Correct Solution:

    To understand the solution, you will need to understand all below problems in order:

    • 0/1 Knapsack with Dynamic Programming
    • Partition Equal Subset Sum with DP
    • Solution

    My Code (Same logic as this):

    #include
    #define rep(i,_n) for(int i=0;i<_n;i++)
    using namespace std;
    
    #define MXN 55
    int arr[MXN];
    int dp[MXN][MXN*MXN];
    
    int main() {
        //code
        int t,N,c;
        cin>>t;
        while(t--){
            rep(i,MXN) fill(dp[i], dp[i]+MXN*MXN, 0);
    
            cin>>N;
            rep(i,N) cin>>arr[i];
            int sum = accumulate(arr, arr+N, 0);
            dp[0][0] = 1;
            for(int i=1; i<=N; i++)
                for(int j=sum; j>=0; j--)
                    dp[i][j] |= (dp[i-1][j] | (j>=arr[i-1] ? dp[i-1][j-arr[i-1]] : 0));
    
            int res = sum;
    
            for(int i=0; i<=sum/2; i++)
                if(dp[N][i]) res = min(res, abs(i - (sum-i)));
    
            cout<

提交回复
热议问题