Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dynamic programming : perfect sum with negative numbers

Given an array of integers and a sum, the task is to print all subsets of given array with sum equal to given sum.

Example: 
Input : arr[] = {1, 2, 3, 4, 5}
        sum = 10
Output : [4 3 2 1]  
         [5 3 2] 
         [5 4 1]

Input : arr[] = {-1, 2, 3, 4, 5}
        sum = 10
Output : [5 3 2] 
         [5 4 2 -1]

I have done that using dynamic programming in pseudo polynomial time. This is an extension of subset sum problem, which only takes care of deciding whether such a subset exist or not. My solution below works for both positive and negative numbers for the subset sum problem. However, it is not able to print the subsets correctly if the array contains negative numbers.The program is-

import java.util.ArrayList;

// sum problem
class GFG {

    static boolean subset[][];

    // Returns true if there is a subset of
    // set[] with sun equal to given sum
    static boolean isSubsetSum(int set[],
                               int n, int sum) {
        // The value of subset[i][j] will be
        // true if there is a subset of
        // set[0..j-1] with sum equal to i
        subset = new boolean[n + 1][sum + 1];

        // Fill the subset table in botton
        // up manner
        for (int i = 0; i <= n; i++) {
            for (int j = 0; j <= sum; j++) {
                if (j == 0) {
                    subset[i][j] = true;
                } else if (i <= 0 && sum >= 1)
                    subset[i][j] = false;
                else if (set[i - 1] > j)
                    subset[i][j] = subset[i - 1][j];
                else {
                    if (set[i - 1] >= 0)
                        subset[i][j] = subset[i - 1][j] || subset[i - 1][j - set[i - 1]];
                    else
                        subset[i][j] = subset[i - 1][j] || subset[i - 1][j + set[i - 1]];
                }
            }
        }

        // uncomment this code to print table
//        for (int i = 0; i <= sum; i++)
//        {
//        for (int j = 0; j <= n; j++)
//            System.out.println (subset[i][j]);
//        }

        return subset[n][sum];
    }

    /* Driver program to test above function */
    public static void main(String args[]) {
        int set[] = {1, 2, 3, 4, 5};
        int sum = 10;
        int n = set.length;
        if (isSubsetSum(set, n, sum) == true)
            System.out.println("Found a subset"
                    + " with given sum");
        else
            System.out.println("No subset with"
                    + " given sum");
        System.out.println("Done");
        ArrayList<Integer> list = new ArrayList<>();
        printSubsets(set, n, sum, list);
        System.out.println("Finished");
    }

    static void display(ArrayList<Integer> v) {
        System.out.println(v);
    }

    private static void printSubsets(int[] set, int i, int sum, ArrayList<Integer> list) {
        if (i == 0 && sum != 0 && subset[0][sum]) {
            list.add(set[i]);
            display(list);
            list.clear();
            return;
        }

        // If sum becomes 0
        if (i == 0 && sum == 0) {
            display(list);
            list.clear();
            return;
        }

        // If given sum can be achieved after ignoring
        // current element.
        if (subset[i - 1][sum]) {
            // Create a new vector to store path
            ArrayList<Integer> b = new ArrayList<>();
            b.addAll(list);
            printSubsets(set, i - 1, sum, b);
        }

        // If given sum can be achieved after considering
        // current element.

        if (sum >= set[i - 1] && subset[i - 1][sum - set[i - 1]]) {
            list.add(set[i - 1]);
            printSubsets(set, i - 1, sum - set[i - 1], list);
        }

    }   
} 

How this code can be modified to work for negative numbers as well?

like image 939
Somesh Dhal Avatar asked Nov 26 '22 00:11

Somesh Dhal


1 Answers

Your solutions assumes that all values are positive, so the dynamic programing array subset is filled with the values of j that are positive, but you need to take into account negative sums now.

What you need to do is to change the loop limits of j to fill the dynamic programing array to

for (int j = negative_sum; j <= positive_sum; j++)

Where negative_sum is the sum of all the negative values and positive_sum is the sum of all the positive ones.

For more details read the wikipedia page for the Subset Sum Problem here where this step is explained.

like image 62
Rolando Urquiza Avatar answered Dec 20 '22 23:12

Rolando Urquiza