diff --git a/dynamic_programming/0_1_knapsack.cpp b/dynamic_programming/0_1_knapsack.cpp index 7ea0c04c6..2e0a82e6a 100644 --- a/dynamic_programming/0_1_knapsack.cpp +++ b/dynamic_programming/0_1_knapsack.cpp @@ -1,66 +1,129 @@ -// 0-1 Knapsack problem - Dynamic programming -//#include +/** + * @file + * @brief Implementation of [0-1 Knapsack Problem] + * (https://en.wikipedia.org/wiki/Knapsack_problem) + * + * @details + * Given weights and values of n items, put these items in a knapsack of + * capacity `W` to get the maximum total value in the knapsack. In other words, + * given two integer arrays `val[0..n-1]` and `wt[0..n-1]` which represent + * values and weights associated with n items respectively. Also given an + * integer W which represents knapsack capacity, find out the maximum value + * subset of `val[]` such that sum of the weights of this subset is smaller than + * or equal to W. You cannot break an item, either pick the complete item or + * don’t pick it (0-1 property) + * + * ### Algorithm + * The idea is to consider all subsets of items and calculate the total weight + * and value of all subsets. Consider the only subsets whose total weight is + * smaller than `W`. From all such subsets, pick the maximum value subset. + * + * @author [Anmol](https://github.com/Anmol3299) + * @author [Pardeep](https://github.com/Pardeep009) + */ + +#include +#include #include -using namespace std; +#include -// void Print(int res[20][20], int i, int j, int capacity) -//{ -// if(i==0 || j==0) -// { -// return; -// } -// if(res[i-1][j]==res[i][j-1]) -// { -// if(i<=capacity) -// { -// cout<res[i][j-1]) -// { -// Print(res, i-1,j, capacity); -// } -// else if(res[i][j-1]>res[i-1][j]) -// { -// Print(res, i,j-1, capacity); -// } -//} +/** + * @namespace dynamic_programming + * @brief Dynamic Programming algorithms + */ +namespace dynamic_programming { +/** + * @namespace Knapsack + * @brief Implementation of 0-1 Knapsack problem + */ +namespace knapsack { +/** + * @brief Picking up all those items whose combined weight is below + * given capacity and calculating value of those picked items.Trying all + * possible combinations will yield the maximum knapsack value. + * @tparam n size of the weight and value array + * @param capacity capacity of the carrying bag + * @param weight array representing weight of items + * @param value array representing value of items + * @return maximum value obtainable with given capacity. + */ +template +int maxKnapsackValue(const int capacity, const std::array &weight, + const std::array &value) { + std::vector > maxValue(n + 1, + std::vector(capacity + 1, 0)); + // outer loop will select no of items allowed + // inner loop will select capcity of knapsack bag + int items = sizeof(weight) / sizeof(weight[0]); + for (size_t i = 0; i < items + 1; ++i) { + for (size_t j = 0; j < capacity + 1; ++j) { + if (i == 0 || j == 0) { + // if no of items is zero or capacity is zero, then maxValue + // will be zero + maxValue[i][j] = 0; + } else if (weight[i - 1] <= j) { + // if the ith item's weight(in actual array it will be at i-1) + // is less than or equal to the allowed weight i.e. j then we + // can pick that item for our knapsack. maxValue will be the + // obtained either by picking the current item or by not picking + // current item -int Knapsack(int capacity, int n, int weight[], int value[]) { - int res[20][20]; - for (int i = 0; i < n + 1; ++i) { - for (int j = 0; j < capacity + 1; ++j) { - if (i == 0 || j == 0) - res[i][j] = 0; - else if (weight[i - 1] <= j) - res[i][j] = max(value[i - 1] + res[i - 1][j - weight[i - 1]], - res[i - 1][j]); - else - res[i][j] = res[i - 1][j]; + // picking current item + int profit1 = value[i - 1] + maxValue[i - 1][j - weight[i - 1]]; + + // not picking current item + int profit2 = maxValue[i - 1][j]; + + maxValue[i][j] = std::max(profit1, profit2); + } else + // as weight of current item is greater than allowed weight, so + // maxProfit will be profit obtained by excluding current item. + maxValue[i][j] = maxValue[i - 1][j]; } } - // Print(res, n, capacity, capacity); - // cout<<"\n"; - return res[n][capacity]; + + // returning maximum value + return maxValue[items][capacity]; } +} // namespace knapsack +} // namespace dynamic_programming + +/** + * @brief Function to test above algorithm + * @returns void + */ +static void test() { + // Test 1 + const int n1 = 3; // number of items + std::array weight1 = {10, 20, 30}; // weight of each item + std::array value1 = {60, 100, 120}; // value of each item + const int capacity1 = 50; // capacity of carrying bag + const int max_value1 = dynamic_programming::knapsack::maxKnapsackValue( + capacity1, weight1, value1); + const int expected_max_value1 = 220; + assert(max_value1 == expected_max_value1); + std::cout << "Maximum Knapsack value with " << n1 << " items is " + << max_value1 << std::endl; + + // Test 2 + const int n2 = 4; // number of items + std::array weight2 = {24, 10, 10, 7}; // weight of each item + std::array value2 = {24, 18, 18, 10}; // value of each item + const int capacity2 = 25; // capacity of carrying bag + const int max_value2 = dynamic_programming::knapsack::maxKnapsackValue( + capacity2, weight2, value2); + const int expected_max_value2 = 36; + assert(max_value2 == expected_max_value2); + std::cout << "Maximum Knapsack value with " << n2 << " items is " + << max_value2 << std::endl; +} + +/** + * @brief Main function + * @returns 0 on exit + */ int main() { - int n; - cout << "Enter number of items: "; - cin >> n; - int weight[n], value[n]; - cout << "Enter weights: "; - for (int i = 0; i < n; ++i) { - cin >> weight[i]; - } - cout << "Enter values: "; - for (int i = 0; i < n; ++i) { - cin >> value[i]; - } - int capacity; - cout << "Enter capacity: "; - cin >> capacity; - cout << Knapsack(capacity, n, weight, value); + // Testing + test(); return 0; }