6

I'm doing a Knapsack in Java where we only use weights no value. The weightlimit is 1000. We get 5 weights scanned from keyboard which we use. The twist is that you can actually go over 1000 aslong as its the closets to 1000. So in one scenario we have 2 possible weights 990 and 1010 and the program is suposed to pick the higher one. The scanned numbers can never be higher then 1000.

package kapsackidone;
import java.util.Scanner;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.*;
public class Kapsack {

public static void main(String[] args) throws Exception {
    BufferedReader reader=new BufferedReader(new InputStreamReader(System.in));

    int [] wt=new int[5];
    int W = 1000;

    System.out.println("Enter Weight 5 weights");
    for(int i=0; i<5; i++)
    {
        wt[i]=Integer.parseInt(reader.readLine());
    }   
    System.out.println(knapsack(wt, W));
}

public static int knapsack(int wt[], int W) {
    int N = wt.length;
    int[][] V = new int[N + 1][W + 1];

    for (int col = 0; col <= W; col++) {
        V[0][col] = 0;
    }


    for (int row = 0; row <= N; row++) {
        V[row][0] = 0;
    }

    for (int item=1;item<=N;item++){

    for (int weight=1;weight<=W;weight++){
        if(wt[item-1] > weight)
        {
            V[item][weight] = V[item-1][weight];
        }
        else if((weight - V[item-1][weight]) < (weight - (V[item-1][weight - wt[item-1]] + wt[item-1])))
        {
            V[item][weight] = V[item-1][weight];
        }
        else
        {
            V[item][weight] = V[item-1][weight - wt[item-1]] + wt[item-1];
        }
    }
    }

    return V[N][W];
    }
}

I am really struggling with how I can get this done. Before you ask no its not homework im gonna be a project manager for a new group of people that consist of developers so im just trying to learn some java so that i understand a bit of what they do even tho i doubt i will be able to help with the coding.

  • The problem is that the second-smallest weight (the smallest possible value of an infeasible solution) can be arbitrarily large. Consider two items `i1=1` and `i2=M` where `M` is a nonnegative integer; suppose the knapsack capacity is `1`. The only feasible solution is `i1` with a weight of `1`, while the smallest infeasible solution is `i2` with value `M`. As `M` goes to infinity, neither `M-1` (the additive distance to the optimum) nor `M/1` (the ratio of the optimum and smallest possible violation of the capacity) is bounded. – Codor Dec 04 '15 at 07:45
  • So this is the task i found online on kattis. we wanna lift as close to 1000 kg as possible. In case there exist two such numbers which are equally close to 1000 (e.g. 998 and 1002), We will pick the greater one (in this case 1002). Input The first line of the input contains the number of plates n (1≤n≤1000). Each of the following n lines contains one positive integer less than or equal to 1000, denoting the weight of each plate. Output Output one integer, the combined weight closest to 1000. – Filip Gustafsson Dec 04 '15 at 08:06
  • 1
    i forgot to say that the weight is constant 1000 and that the scanned numbers can never be more than 1000 they can only be 500 and 700 which would equal the sum 1200 but one single weight can never be over 1000 – Filip Gustafsson Dec 04 '15 at 08:17

4 Answers4

2

I would just run it twice.

In first run find the "classic" solution with best weight less than 1000.

In second run, increase the max value 1000 to the max possible value which is allowed based on previous solution.

Dont worry about "it is two times slower", multiplying complexity by constant does not change the complexity, which is the important thing in knapsack problem.


If your code is working then you can probably count the best solution as this

System.out.println(knapsack(wt,2*W - knapsack(wt, W));

Or you can write it as this to be more clear what is happening (it does exactly the same as that one-line above)

int bestClassicSolution = knapsack(wt, W);
int differenceAgainstMaxWeight = W - bestClassicSolution;
int newMaxWeight = W + differenceAgainstMaxWeight;
int bestSolution = knapsack(wt, newMaxWeight);
System.out.println(bestSolution);

EDIT : The solution above works for this condition select as big solution as possible, but it must not differ from 1000 more than "below 1000" best solution. The OP actually wants little different thing - the "limit" stays, but it should be the closest to the 1000 but as high as possible.


So real solution would to create reversed knapsack method, which will find the solution with minimum value BUT must be bigger than "min" variable.

public static void main(String[] args) throws Exception {
    BufferedReader reader=new BufferedReader(new InputStreamReader(System.in));

    int [] wt=new int[5];
    int W = 1000;

    System.out.println("Enter Weight 5 weights");
    for(int i=0; i<5; i++)
    {
        wt[i]=Integer.parseInt(reader.readLine());
    }   
    int bestClassicSolution = knapsack(wt, W);
    int differenceAgainstMaxWeight = W - bestClassicSolution;
    int newMaxWeight = W + differenceAgainstMaxWeight;
    int bestMaxSolution = reversedKnapsack(wt, newMaxWeight, W);
    int differenceAgainstWeightAboveW = W - bestMaxSolution;

    if (differenceAgainstWeightAboveW <= differenceAgainstMaxWeight){
        System.out.println(bestMaxSolution);
    } else {
        System.out.println(bestClassicSolution);
    }
}

public static int reversedKnapsack(int wt[], int W, int min) {
    //similar to knapsack method, but the solution must be as small as possible and must be bigger than min variable
}
libik
  • 22,239
  • 9
  • 44
  • 87
  • Huh what is your third paragraph supposed to mean? – xrisk Dec 04 '15 at 09:50
  • The knapsack is the famous "NPC problem" and the complexity is important thing too :). What is interesting - it really does not matter if program is two times faster or slower as long as it does not change complexity. – libik Dec 04 '15 at 09:53
  • well you can turn it in on the site and get it graded, check runtime etc and do be able to do that i would need it to work both ways in 1 run i think. – Filip Gustafsson Dec 04 '15 at 10:05
  • it will be "one run", just add for-cycle that runs it twice... If you want to make it fast, use backtracking and cut the branches with no solution, it can change the runtime much more than "run one" or "run twice". Also the runtime will probably check the complexity is not bigger than (2^n) – libik Dec 04 '15 at 10:09
  • could you show me in a code example how it could be done.. as i said im not a developer just trying to learn and the alogritms dosent really translate well with me to code. sorry if im a bother .. – Filip Gustafsson Dec 04 '15 at 10:23
  • Tried it with the inputs 500,600,700,800,700 and it picked 1200 instead of 1100 not sure why – Filip Gustafsson Dec 04 '15 at 10:43
  • _In second run, increase the max value 1000 to the max possible value which is allowed based on previous solution._ - and what would be the value of the permitted weight? To my understanding, it cannot be known beforehand. – Codor Dec 04 '15 at 10:44
  • @fammy - ach, I thought it was "select as big solution as possible, but it must not differ from 1000 more than "below 1000" best solution . – libik Dec 04 '15 at 10:50
  • @Codor - value would be `W - knapsack(wt, W)` – libik Dec 04 '15 at 10:52
  • @libik yes exactly, you want it as close to 1000. so if the scenario is 997 and 1003 it would pick the higher just because it prioritize higher numbers if the distance from 1000 is the same. – Filip Gustafsson Dec 04 '15 at 11:00
  • @fammy - ok, now this solution should work, but it would require to create one more method by you. – libik Dec 04 '15 at 11:21
  • @libik which method ? i still have an bugg because when i use inputs, 500,600,700,800,5 the program choses 1105 instead of 1100. – Filip Gustafsson Dec 04 '15 at 11:27
  • okey @libik think i get the concept of why we need the metod but i am not sure how i would do this reversed kapsack. – Filip Gustafsson Dec 04 '15 at 11:57
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/97005/discussion-between-fammy-and-libik). – Filip Gustafsson Dec 04 '15 at 18:27
0

Verbatim from Wikipedia — Subset sum problem.

The problem can be solved in pseudo-polynomial time using dynamic programming. Suppose the sequence is

x1, ..., xN and we wish to determine if there is a nonempty subset which sums to zero. Define the boolean-valued function Q(i, s) to be the value (true or false) if

"there is a nonempty subset of x1, ..., xi which sums to s". Thus, the solution to the problem "Given a set of integers, is there a non-empty subset whose sum is zero?" is the value of Q(N, 0).

Let A be the sum of the negative values and B the sum of the positive values. Clearly, Q(i, s) = false, if s < A or s > B. So these values do not need to be stored or computed.

Create an array to hold the values Q(i, s) for 1 ≤ i ≤ N and A ≤ s ≤ B.

The array can now be filled in using a simple recursion. Initially, for A ≤ s ≤ B, set

Q(1, s) := (x1 == s) where == is a boolean function that returns true if x1 is equal to s, false otherwise.

Then, for i = 2, …, N, set

Q(i, s) := Q(i − 1, s) or (xi == s) or Q(i − 1, s − xi), for A ≤ s ≤ B.

After computing the values of Q, we may loop through them, and take the true value which is closest to the limit.

As for the value of S, we need to take the sum of the weights given to us.

xrisk
  • 3,790
  • 22
  • 45
  • wassnt me who downvoted but as i stated above, the algoritms dosent really help me since im a bit of a novice at coding and therefore code examples makes it much easier for me to understand cause then i can search the keywords and read up on examples in code rather than math. – Filip Gustafsson Dec 04 '15 at 12:00
0

The classical knapsack problem is discussed in a Wikipedia article; the dynamic programming formulation for the classical problem can be adapted to the following problem.

Given weights w_1,...,w_n and a target capacity W, find a subset of the items for which the total weight is minimal, but larger than W.

To avoid pathological cases, we assume that the sum of the weights is largert than W, otherwise there is no solution. Let W_MAX denote the sum of all weights.

For the dynamic programming formulation, let

m[i,j] for each i in 0,...,n and j in 0,...,W_MAX

denote the minimum weight larger than W attainable by discarding weights from 0,...,i with total weight exactly j.

We obtain

m[0,j] = W_MAX for each j in 0,...n

and get the recurrence relation

m[i,j] = min {
               m[i-1, i       ],       // corresponds to keeping weight i
               m[i-1, j - w[i]] - w[i] // corresponds to discarding weight i
             }

and evaluation can be implemented by iterating i=0,...,n and j=0,...,W_MAX; accedd to m outside of these bounds must be assumed to yield W_MAX. Similar to the classical knapsack problem, the actual set of items to discard can be found by backtracking.

Finally, the given instance can be optimized twice; first with the algorithm above, then with the classical knapsack algorithm.

Codor
  • 17,447
  • 9
  • 29
  • 56
0

I would evaluate this problem first as a classical knapsack problem taking
value[i] = weight[i] ;
, where i is the i'th item and maximum weight to be the given max_wt (1000 kg) and item[] be an array containing the items in ascending order of their weights .

Let the answer of this problem be x , say 990 kg , now i would calculate the difference 'd' ,
d = max_wt - x ;
iterate over item[] till item[i] exceeds d :
int i = 0 ; while(item[i] < d ) i++; ,lastly add the first item that exceeds 'd' to the answer you got through the classical knapsack problem :
answer = dp[n-1][w-1] + item[i] \\dp[n-1][w-1] is the answer of the classical \\knapsack problem

95_96
  • 341
  • 2
  • 12