1
1
/* *
2
2
* @file
3
3
* @brief Implementation of the Unbounded 0/1 Knapsack Problem
4
- *
5
- * @details
6
- * The Unbounded 0/1 Knapsack problem allows taking unlimited quantities of each item.
7
- * The goal is to maximize the total value without exceeding the given knapsack capacity.
8
- * Unlike the 0/1 knapsack, where each item can be taken only once, in this variation,
9
- * any item can be picked any number of times as long as the total weight stays within
10
- * the knapsack's capacity.
11
- *
12
- * Given a set of N items, each with a weight and a value, represented by the arrays
13
- * `wt` and `val` respectively, and a knapsack with a weight limit W, the task is to
14
- * fill the knapsack to maximize the total value.
15
4
*
16
- * @note weight and value of items is greater than zero
5
+ * @details
6
+ * The Unbounded 0/1 Knapsack problem allows taking unlimited quantities of each
7
+ * item. The goal is to maximize the total value without exceeding the given
8
+ * knapsack capacity. Unlike the 0/1 knapsack, where each item can be taken only
9
+ * once, in this variation, any item can be picked any number of times as long
10
+ * as the total weight stays within the knapsack's capacity.
11
+ *
12
+ * Given a set of N items, each with a weight and a value, represented by the
13
+ * arrays `wt` and `val` respectively, and a knapsack with a weight limit W, the
14
+ * task is to fill the knapsack to maximize the total value.
15
+ *
16
+ * @note weight and value of items is greater than zero
17
17
*
18
18
* ### Algorithm
19
- * The approach uses dynamic programming to build a solution iteratively.
20
- * A 2D array is used for memoization to store intermediate results, allowing
19
+ * The approach uses dynamic programming to build a solution iteratively.
20
+ * A 2D array is used for memoization to store intermediate results, allowing
21
21
* the function to avoid redundant calculations.
22
- *
22
+ *
23
23
* @author [Sanskruti Yeole](https://github.com/yeolesanskruti)
24
24
* @see dynamic_programming/0_1_knapsack.cpp
25
25
*/
26
26
27
+ #include < cassert> // For using assert function to validate test cases
28
+ #include < cstdint> // For fixed-width integer types like std::uint16_t
27
29
#include < iostream> // Standard input-output stream
28
- #include < vector> // Standard library for using dynamic arrays (vectors)
29
- #include < cassert> // For using assert function to validate test cases
30
- #include < cstdint> // For fixed-width integer types like std::uint16_t
30
+ #include < vector> // Standard library for using dynamic arrays (vectors)
31
31
32
32
/* *
33
33
* @namespace dynamic_programming
@@ -42,7 +42,7 @@ namespace dynamic_programming {
42
42
namespace unbounded_knapsack {
43
43
44
44
/* *
45
- * @brief Recursive function to calculate the maximum value obtainable using
45
+ * @brief Recursive function to calculate the maximum value obtainable using
46
46
* an unbounded knapsack approach.
47
47
*
48
48
* @param i Current index in the value and weight vectors.
@@ -52,27 +52,33 @@ namespace unbounded_knapsack {
52
52
* @param wt Vector of weights corresponding to the items.
53
53
* @note "wt" data type can be changed according to the size of the input.
54
54
* @param dp 2D vector for memoization to avoid redundant calculations.
55
- * @return The maximum value that can be obtained for the given index and capacity.
55
+ * @return The maximum value that can be obtained for the given index and
56
+ * capacity.
56
57
*/
57
- std::uint16_t KnapSackFilling (std::uint16_t i, std::uint16_t W,
58
- const std::vector<std::uint16_t >& val,
59
- const std::vector<std::uint16_t >& wt,
60
- std::vector<std::vector<int >>& dp) {
58
+ std::uint16_t KnapSackFilling (std::uint16_t i, std::uint16_t W,
59
+ const std::vector<std::uint16_t >& val,
60
+ const std::vector<std::uint16_t >& wt,
61
+ std::vector<std::vector<int >>& dp) {
61
62
if (i == 0 ) {
62
63
if (wt[0 ] <= W) {
63
- return (W / wt[0 ]) * val[0 ]; // Take as many of the first item as possible
64
+ return (W / wt[0 ]) *
65
+ val[0 ]; // Take as many of the first item as possible
64
66
} else {
65
- return 0 ; // Can't take the first item
67
+ return 0 ; // Can't take the first item
66
68
}
67
69
}
68
- if (dp[i][W] != -1 ) return dp[i][W]; // Return result if available
70
+ if (dp[i][W] != -1 )
71
+ return dp[i][W]; // Return result if available
69
72
70
- int nottake = KnapSackFilling (i - 1 , W, val, wt, dp); // Value without taking item i
73
+ int nottake =
74
+ KnapSackFilling (i - 1 , W, val, wt, dp); // Value without taking item i
71
75
int take = 0 ;
72
76
if (W >= wt[i]) {
73
- take = val[i] + KnapSackFilling (i, W - wt[i], val, wt, dp); // Value taking item i
77
+ take = val[i] + KnapSackFilling (i, W - wt[i], val, wt,
78
+ dp); // Value taking item i
74
79
}
75
- return dp[i][W] = std::max (take, nottake); // Store and return the maximum value
80
+ return dp[i][W] =
81
+ std::max (take, nottake); // Store and return the maximum value
76
82
}
77
83
78
84
/* *
@@ -84,68 +90,84 @@ std::uint16_t KnapSackFilling(std::uint16_t i, std::uint16_t W,
84
90
* @param wt Vector of weights corresponding to the items.
85
91
* @return The maximum value that can be obtained for the given capacity.
86
92
*/
87
- std::uint16_t unboundedKnapsack (std::uint16_t N, std::uint16_t W,
88
- const std::vector<std::uint16_t >& val,
89
- const std::vector<std::uint16_t >& wt) {
90
- if (N==0 )return 0 ; // Expect 0 since no items
91
- std::vector<std::vector<int >> dp (N, std::vector<int >(W + 1 , -1 )); // Initialize memoization table
92
- return KnapSackFilling (N - 1 , W, val, wt, dp); // Start the calculation
93
+ std::uint16_t unboundedKnapsack (std::uint16_t N, std::uint16_t W,
94
+ const std::vector<std::uint16_t >& val,
95
+ const std::vector<std::uint16_t >& wt) {
96
+ if (N == 0 )
97
+ return 0 ; // Expect 0 since no items
98
+ std::vector<std::vector<int >> dp (
99
+ N, std::vector<int >(W + 1 , -1 )); // Initialize memoization table
100
+ return KnapSackFilling (N - 1 , W, val, wt, dp); // Start the calculation
93
101
}
94
102
95
- } // unbounded_knapsack
103
+ } // namespace unbounded_knapsack
96
104
97
- } // dynamic_programming
105
+ } // namespace dynamic_programming
98
106
99
107
/* *
100
108
* @brief self test implementation
101
109
* @return void
102
110
*/
103
111
static void tests () {
104
112
// Test Case 1
105
- std::uint16_t N1 = 4 ; // Number of items
106
- std::vector<std::uint16_t > wt1 = {1 , 3 , 4 , 5 }; // Weights of the items
107
- std::vector<std::uint16_t > val1 = {6 , 1 , 7 , 7 }; // Values of the items
108
- std::uint16_t W1 = 8 ; // Maximum capacity of the knapsack
113
+ std::uint16_t N1 = 4 ; // Number of items
114
+ std::vector<std::uint16_t > wt1 = {1 , 3 , 4 , 5 }; // Weights of the items
115
+ std::vector<std::uint16_t > val1 = {6 , 1 , 7 , 7 }; // Values of the items
116
+ std::uint16_t W1 = 8 ; // Maximum capacity of the knapsack
109
117
// Test the function and assert the expected output
110
- assert (unboundedKnapsack (N1, W1, val1, wt1) == 48 );
111
- std::cout << " Maximum Knapsack value " << unboundedKnapsack (N1, W1, val1, wt1) << std::endl;
118
+ assert (dynamic_programming::unbounded_knapsack::unboundedKnapsack (
119
+ N1, W1, val1, wt1) == 48 );
120
+ std::cout << " Maximum Knapsack value "
121
+ << dynamic_programming::unbounded_knapsack::unboundedKnapsack (
122
+ N1, W1, val1, wt1)
123
+ << std::endl;
112
124
113
125
// Test Case 2
114
- std::uint16_t N2 = 3 ; // Number of items
115
- std::vector<std::uint16_t > wt2 = {10 , 20 , 30 }; // Weights of the items
116
- std::vector<std::uint16_t > val2 = {60 , 100 , 120 }; // Values of the items
117
- std::uint16_t W2 = 5 ; // Maximum capacity of the knapsack
126
+ std::uint16_t N2 = 3 ; // Number of items
127
+ std::vector<std::uint16_t > wt2 = {10 , 20 , 30 }; // Weights of the items
128
+ std::vector<std::uint16_t > val2 = {60 , 100 , 120 }; // Values of the items
129
+ std::uint16_t W2 = 5 ; // Maximum capacity of the knapsack
118
130
// Test the function and assert the expected output
119
- assert (unboundedKnapsack (N2, W2, val2, wt2) == 0 );
120
- std::cout << " Maximum Knapsack value " << unboundedKnapsack (N2, W2, val2, wt2) << std::endl;
131
+ assert (dynamic_programming::unbounded_knapsack::unboundedKnapsack (
132
+ N2, W2, val2, wt2) == 0 );
133
+ std::cout << " Maximum Knapsack value "
134
+ << dynamic_programming::unbounded_knapsack::unboundedKnapsack (
135
+ N2, W2, val2, wt2)
136
+ << std::endl;
121
137
122
138
// Test Case 3
123
- std::uint16_t N3 = 3 ; // Number of items
124
- std::vector<std::uint16_t > wt3 = {2 , 4 , 6 }; // Weights of the items
125
- std::vector<std::uint16_t > val3 = {5 , 11 , 13 };// Values of the items
126
- std::uint16_t W3 = 27 ;// Maximum capacity of the knapsack
139
+ std::uint16_t N3 = 3 ; // Number of items
140
+ std::vector<std::uint16_t > wt3 = {2 , 4 , 6 }; // Weights of the items
141
+ std::vector<std::uint16_t > val3 = {5 , 11 , 13 }; // Values of the items
142
+ std::uint16_t W3 = 27 ; // Maximum capacity of the knapsack
127
143
// Test the function and assert the expected output
128
- assert (unboundedKnapsack (N3, W3, val3, wt3) == 27 );
129
- std::cout << " Maximum Knapsack value " << unboundedKnapsack (N3, W3, val3, wt3) << std::endl;
144
+ assert (dynamic_programming::unbounded_knapsack::unboundedKnapsack (
145
+ N3, W3, val3, wt3) == 27 );
146
+ std::cout << " Maximum Knapsack value "
147
+ << dynamic_programming::unbounded_knapsack::unboundedKnapsack (
148
+ N3, W3, val3, wt3)
149
+ << std::endl;
130
150
131
151
// Test Case 4
132
- std::uint16_t N4 = 0 ; // Number of items
133
- std::vector<std::uint16_t > wt4 = {}; // Weights of the items
134
- std::vector<std::uint16_t > val4 = {}; // Values of the items
135
- std::uint16_t W4 = 10 ; // Maximum capacity of the knapsack
136
- assert (unboundedKnapsack (N4, W4, val4, wt4) == 0 );
137
- std::cout << " Maximum Knapsack value for empty arrays: " << unboundedKnapsack (N4, W4, val4, wt4) << std::endl;
138
-
139
- std::cout << " All test cases passed!" << std::endl;
152
+ std::uint16_t N4 = 0 ; // Number of items
153
+ std::vector<std::uint16_t > wt4 = {}; // Weights of the items
154
+ std::vector<std::uint16_t > val4 = {}; // Values of the items
155
+ std::uint16_t W4 = 10 ; // Maximum capacity of the knapsack
156
+ assert (dynamic_programming::unbounded_knapsack::unboundedKnapsack (
157
+ N4, W4, val4, wt4) == 0 );
158
+ std::cout << " Maximum Knapsack value for empty arrays: "
159
+ << dynamic_programming::unbounded_knapsack::unboundedKnapsack (
160
+ N4, W4, val4, wt4)
161
+ << std::endl;
140
162
163
+ std::cout << " All test cases passed!" << std::endl;
141
164
}
142
165
143
166
/* *
144
167
* @brief main function
145
168
* @return 0 on successful exit
146
169
*/
147
170
int main () {
148
- tests (); // Run self test implementation
171
+ tests (); // Run self test implementation
149
172
return 0 ;
150
173
}
151
-
0 commit comments