-1

Problem: Given an integers array A[], length = n and a given integer value TARGET. Find the subsequence (might not be contiguous) satisfied that its sum is less than TARGET and nearest to that TARGET.

Eg.: A[] = [10, -2, 3, 7]. TARGET = 14. Answer = {10, 3}

I ran into this problem in a Hackerrank challenge, that I couldn't figure out any polynomial time solution, it first sounds quite familiar to some of dynamic programming problems, but this case the conditions 'No greater than' and 'nearest' seem eliminate that solution.

From my first thought following dynamic programming approach, at the i-problem (i=0->n-1), we need to evaluate all sub-sequences that either containing A[i] or not containing A[i], the latter is known as S[i-1], so just focus on all sub-sequences having A[i] as the last element.

That where we can't just rely on previous solved problems (0->i-1) as the sum we need must be less than and nearest to target might not be yielded from the smaller solutions, it might be produced from the second one, third one plus the last element A[i], and iterating over all subsequence containing A[i] would need to go through all 2^i - 1 subsets, excluding the single set {A[i]}.

Any suggestion on this kind of problem?

Arcobaleno
  • 484
  • 1
  • 5
  • 14

3 Answers3

0

This is a case of the knapsack problem where the 'values' are equal to the weights of the items and TARGET is the capacity of the knapsack.

Apply the dynamic programming solution that runs in pseudo-polynomial time with respect to the input size.

Abhishek Bansal
  • 12,589
  • 4
  • 31
  • 46
0

This is not very hard problem, easier than knapsack problem. The next code solve your problem:

#include <iostream>
#include <vector>
#include <algorithm>
#include <set>
#include<cstring>
#include <math.h>
#include<cstdio>
#include<string>
#include <queue>
#include <list>

using namespace std;


int main(){
    int dp[100000];
    int way[100000];
    memset(dp,0,sizeof(dp));
    memset(way,0,sizeof(way));
    int *dpTmp = dp+50000;
    int *wayTmp = way+50000;
    dpTmp[0] = 1;
    wayTmp[0] = -1;
    int A[]={10,-2, 3, 7};
    int TARGET = 14;
    int n=4;
    for(int i=0; i<n; i++){
        if(A[i]<0){
            for(int j=-50000; j<50000; j++){
                if(dpTmp[j] == 1 && dpTmp[j+A[i]] == 0){
                    dpTmp[j+A[i]] = 1;
                    wayTmp[j+A[i]] = i;
                }
            }
        }else{
            for(int j=49999; j>=-50000; j--){
                if(dpTmp[j] == 1 && dpTmp[j+A[i]] == 0){
                    dpTmp[j+A[i]] = 1;
                    wayTmp[j+A[i]] = i;
                }
            }
        }
    }
    int inc = 1;
    if(TARGET>0){
        inc = -1;
    }else{
        inc = 1;
    }
    TARGET += inc;
    while(dpTmp[TARGET] == 0) TARGET+=inc;
    cout<<TARGET<<endl;
    while(wayTmp[TARGET] != -1){
        cout<<A[wayTmp[TARGET]]<<" ";
        TARGET -= A[wayTmp[TARGET]];
    }
    cout<<endl;
    return 0;
}
0
/**
     * @param m: An integer m denotes the size of a backpack
     * @param A: Given n items with each of size A[i]
     * @return: The maximum total size of items under the limit of size m
     */

int backPack(int m, vector<int> A) {
        // use one dimensional V to represent two dimensional m
        vector<int> V(m+1,0);
        for(int i=0;i<A.size();i++)
        {
            for(int j=m;j>=A[i];j--)
            {
                V[j] = max(V[j], V[j-A[i]] + A[i]);
            }
        }
        return V[m];
    }
Peiti Li
  • 4,634
  • 9
  • 40
  • 57