The 0-1 Knapsack Problem (AKA The Discrete Knapsack Problem) is a famous problem solvable by dynamic-programming. In this article, I describe the problem, the most common algorithm used to solve it and then provide a sample implementation in C.
If you’ve never heard of the Knapsack Problems before, it will help to read this previous post.
The Problem
The Discrete (0-1) Knapsack Problem usually sounds like this:
Little Red Riding Hood wants to bring grandma a basket of goodies. She has an unlimited supply of n types of sweets each weighting c[i] and having the nutritional value of v[i]. Her basket can hold at most W kilograms of sweets.
Given n, c, v and W, figure out which sweets and how many to take so that the nutritional value in maximal.
So, for this input:
n = 3
c = {8, 6, 4}
v = {16, 10, 7}
W = 10
LRRH should take one of 3 and one of 2, amassing 17 nutritional points.
You’re usually dealling with a knapsack problem when you’re give the cost and the benefits of certain objects and asked to obtain the maximum benefit so that the sum of the costs is smaller than a given value. You have got the Discrete Knapsack Problem when you can only take the whole object or none at all and you have an unlimited supply of objects.
The Algorithm
This is a dynamic-programming algorithm.
The idea is to first calculate the maximum benefit for weight x and only after that to calculate the maximum benefit for x+1. So, on the whole, you first calculate the maximum benefit for 1, then for 2, then for 3, …, then for W-1 and, finally, for W. I store the maximum benefits in an array named a.
Start with a[0] = 0. Then for every a between 1 … W use the formula:
a[i] = max{vj + a(i − cj) | cj ≤ i }
The basic idea is that to reach weight x, you have to add an object of weight w to a previous maximum benefit. More specifically, you have to add w to x – w. Now, there will probably be several ways to reach weight x, so you have to choose the one that maximises the benefit. That’s what the max is for.
Basically, the formula says: “To calculate the benefit of weight x, take every object (value: v; weight: w) and see if the benefit for x – w plus v is greater than the current benefit for x. If so, change it.”
So, for the example, the programme would output (and do) this:
Weight 0; Benefit: 0; Can't reach this exact weight.
Weight 1; Benefit: 0; Can't reach this exact weight.
Weight 2; Benefit: 0; Can't reach this exact weight.
Weight 3; Benefit: 0; Can't reach this exact weight.
Weight 4; Benefit: 7; To reach this weight I added object 3 (7$ 4Kg) to weight 0.
Weight 5; Benefit: 7; To reach this weight I added object 3 (7$ 4Kg) to weight 1.
Weight 6; Benefit: 10; To reach this weight I added object 2 (10$ 6Kg) to weight 0.
Weight 7; Benefit: 10; To reach this weight I added object 2 (10$ 6Kg) to weight 1.
Weight 8; Benefit: 16; To reach this weight I added object 1 (16$ 8Kg) to weight 0.
Weight 9; Benefit: 16; To reach this weight I added object 1 (16$ 8Kg) to weight 1.
Weight 10; Benefit: 17; To reach this weight I added object 2 (10$ 6Kg) to weight 4.
The Programme
This programme runs in pseudo-plynominal time O(n * W). i.e. Slow as hell for large very values of W. Also because it holds to arrays of at least length W, it’s also horribly memory inefficient. Unfortunately, there’s not much you can do.
Here’s the code in C (knapsack10.c):
#include <stdio.h>
#define MAXWEIGHT 100
int n = 3; /* The number of objects */
int c[10] = {8, 6, 4}; /* c[i] is the *COST* of the ith object; i.e. what
YOU PAY to take the object */
int v[10] = {16, 10, 7}; /* v[i] is the *VALUE* of the ith object; i.e.
what YOU GET for taking the object */
int W = 10; /* The maximum weight you can take */
void fill_sack() {
int a[MAXWEIGHT]; /* a[i] holds the maximum value that can be obtained
using at most i weight */
int last_added[MAXWEIGHT]; /* I use this to calculate which object were
added */
int i, j;
int aux;
for (i = 0; i <= W; ++i) {
a[i] = 0;
last_added[i] = -1;
}
a[0] = 0;
for (i = 1; i <= W; ++i)
for (j = 0; j < n; ++j)
if ((c[j] <= i) && (a[i] < a[i - c[j]] + v[j])) {
a[i] = a[i - c[j]] + v[j];
last_added[i] = j;
}
for (i = 0; i <= W; ++i)
if (last_added[i] != -1)
printf("Weight %d; Benefit: %d; To reach this weight I added object %d (%d$ %dKg) to weight %d.\n", i, a[i], last_added[i] + 1, v[last_added[i]], c[last_added[i]], i - c[last_added[i]]);
else
printf("Weight %d; Benefit: 0; Can't reach this exact weight.\n", i);
printf("---\n");
aux = W;
while ((aux > 0) && (last_added[aux] != -1)) {
printf("Added object %d (%d$ %dKg). Space left: %d\n", last_added[aux] + 1, v[last_added[aux]], c[last_added[aux]], aux - c[last_added[aux]]);
aux -= c[last_added[aux]];
}
printf("Total value added: %d$\n", a[W]);
}
int main(int argc, char *argv[]) {
fill_sack();
return 0;
}
That’s it. Good luck. Always open to comments.
2007-11-20 at 21:11
[...] scvalex added an interesting post on The 0-1 Knapsack Problem [...]
2007-11-21 at 7:56
[...] here for full story Der Beitrag wurde am Tuesday, den 20. November 2007 um 11:14 Uhr [...]
2008-08-05 at 10:45
its good program, but it will be best if we can input the elemnts arry at first of program, so can you modify the program so we can input the array as we wish!
2008-11-10 at 7:47
oh thank u
2008-11-10 at 20:20
The code is great
Thanx
2009-03-07 at 12:43
Yelo, can somebody modify the programe code that you can enter the cost and the value of parts and the maximum weight you can take??
It would be great, when it,s possible please send it by mail i would be very grateful:}
greeting Miro
2009-03-07 at 12:44
Here is my mail:) misq51@o2.pl
2009-03-18 at 4:25
is there bug in the program?
I tried to modify the value of c and v, into, let say:
c[]={3,4,5}
v[]={5,7,8}
w remain 10
from logic, we can say the max benefit is 15, but the program return 17…
2009-07-09 at 19:22
The max benefit is 17.
If you take 2 of 1, and 1 of 2.
Then you have weight
3, 3, 4 = 10, and value
5, 5, 7 = 17
2009-03-18 at 4:53
I guess I found out the reason.
during the if(c[j]<=1 …. ), you did not check if the item reuse.
maybe your problem is different from mine, your item can reuse, my problem cant reuse the item.
2009-03-20 at 19:19
how to check it?? that the item was reuse?
2009-03-20 at 19:54
For example, to reach weight 3, I added item 1; to reach weight 6, I added item 1 again… that’s the problem.
To prevent it from reuse, I added a table to record down, if the item was used for a particular weight, put as 1, else 0.
2009-03-21 at 13:02
can you write this part of the code? and the place were you must add it? thx
2009-03-24 at 14:24
Vhanded can you send me the modified program (c code) on my e-mail?? I would be very grateful :) it’s very important here is my mail: misq51@o2.pl
2009-03-31 at 10:40
//The code that I modified is here:
#include
#define MAXWEIGHT 100
int n = 5;
int c[]={2,4,3,5,7}; //cost aka weight
int v[]={3,7,9,8,4}; //value aka benefit
int W=15; //maximum weight can take(bag size)
int main()
{
int table[W][n];
for(int i=0; i<=W; i++)
{
for(int j=0; j<n; j++)
{
table[i][j]=0;
}
}
int a[W]; //this hold the maximum value that can can be obtained using at most i weight
for(int i=0; i<=W; i++)
{
a[i]=0;
}
for(int i=1; i<=W; ++i)
{
for(int j=0; j<n; ++j)
{
if((c[j]<=i)&&(a[i]<=(a[i-c[j]]+v[j]))&&table[i-c[j]][j]!=1)
//c[j]<=i, to allow only if selected weight bucket is less than i
//(a[i]<=(a[i-c[j]]+v[j]), to check if the previous weight bucket has closer value.
//table[i-c[j]][j]!=1 is to prevent the items reuse.
{
for(int k=0; k=a[i])
{
table[i][j]=1;
}
a[i]=newTotalBenefit;
}
}
}
printf(“\t”);
for(int i=0; i<n; i++)
{
printf(“%d “,i);
}
printf(“\n”);
for(int i=0; i<=W; i++)
{
printf(“%d\t”, i);
for(int j=0; j<n; j++)
{
printf(“%d “,table[i][j]);
}
printf(“\n”);
}
printf(“\nmax benefit = %d”, a[W]);
}
//hope it helps.
2009-04-18 at 0:12
i am new to the knapsack problem
but it looks like that the lrrh problem described is an unbound knapsack problem.
2009-04-18 at 5:34
yup, it is. The solution I posted up is bounded.
2009-09-28 at 6:08
its cool thank you
2009-09-28 at 6:11
thx you its good
2009-11-04 at 17:47
Thank U so very much .. this post was very helpful in my studies …