I'm trying to solve the following problem:
Example output: {3,0,2,1}
means 3 of item1
, 0 of item2
, 2 of item3
, and 1 of item4
.
In case I wasn't very clear with the explanation, imagine it's about putting food on a backpack. Each type of food has a weight, a volume, a number of calories and a value and there's a certain amount of each type of food available. The objective would be to maximize the value of the food in the backpack without exceeding a certain maximum amount of weight, volume and calories.
On this scenario the INPUT could be:
Array<Food>:
int MaxWeight = 10; int MaxVolume = 15; int MaxCalories = 10;
Since the data set is quite small (say 7 types of items and there's no more than 15 pieces of each item available), I thought of a brute force search:
R(s)
which takes a set (array of how many of each item) as input, if the input is invalid, it returns. If the input is valid it first updates B (in case s
better than B) and then calls R(s + p_i)
for every product p_iThe idea is to first call R(s) with s = empty set (0 for every product) and every possible branch will be created while the branches that exceed the weights are ignored.
This obviously didn't work cause the amount of branches that have to be checked is huge even for only as few as 7 items
Any help is much appreciated!
You have to consider each type of weight in your DP method. I'll write the implementation in C++:
vector<Food> Array;
int memo[MAX_ITEM][MAX_WEIGHT1][MAX_WEIGHT2][MAX_WEIGHT3];
int f(int ind, int weight1, int weight2, int weight3){
if(weight1<0 || weight2<0 || weight3<0) return -INF;
if(ind == Array.size()) return 0;
int &ret= memo[ind][weight1][weight2][weight3];
if(ret>0) return ret;
int res = 0;
for(int i=0;i<=Array[ind].maxOfType;i++)
res = max(res, i * Array[ind].value + f(ind+1, weight1-i*Array[ind].weight1, weight2-i*Array[ind].weight2, weight3-i*Array[ind].weight3));
return ret = res;
}
The DP function is recursive and we use memoization to optimize it. It returns the maximum value we can get. you can call it by:
f(0,MaxWeight1, MaxWeight2, MaxWeight3);
After that we have to track and see which items leads to maximum value. The Next method will print what you want:
void printResult(int ind, int weight1, int weight2, int weight3){
if(ind == Array.size()) return;
int maxi = memo[ind][weight1][weight2][weight3];
for(int i=0;i<=Array[ind].maxOfType;i++){
int cur = i * Array[ind].value + f(ind+1, weight1-i*Array[ind].weight1, weight2-i*Array[ind].weight2, weight3-i*Array[ind].weight3);
if(cur == maxi){
cout<<i<<", ";
printResult(ind+1, weight1-i*Array[ind].weight1, weight2-i*Array[ind].weight2, weight3-i*Array[ind].weight3);
break;
}
}
}
All codes are tested and works well.