1+ # 0/1 Knapsack Problem (Dynamic Programming)
2+ #
3+ # The 0/1 Knapsack problem is one of the most classic problems in dynamic programming.
4+ # Given a set of items, each with a weight and a value, determine the maximum total value
5+ # you can obtain by putting items in a knapsack with a fixed capacity. Each item can
6+ # either be included (1) or excluded (0) — hence the name "0/1".
7+ #
8+ # Time Complexity: O(n * W) where n = number of items, W = knapsack capacity
9+ # Space Complexity: O(n * W) for full DP table, O(W) for optimized version
10+ #
11+ # Applications:
12+ # - Budget allocation problems
13+ # - Resource optimization (CPU scheduling, project selection)
14+ # - Portfolio selection in finance
15+ # - Cargo loading and packing
16+ # - Subset optimization in AI planning
17+
18+ # Classic DP solution for 0/1 Knapsack
19+ knapsack_01 <- function (weights , values , capacity ) {
20+ # ' Solve 0/1 Knapsack Problem using Dynamic Programming
21+ # ' @param weights: Numeric vector of item weights
22+ # ' @param values: Numeric vector of item values
23+ # ' @param capacity: Maximum weight capacity of the knapsack
24+ # ' @return: List containing max value, selected items, and DP table
25+
26+ n <- length(values )
27+
28+ # Handle edge case
29+ if (n == 0 || capacity == 0 ) {
30+ return (list (
31+ max_value = 0 ,
32+ selected_items = c(),
33+ dp_table = matrix (0 , nrow = n + 1 , ncol = capacity + 1 )
34+ ))
35+ }
36+
37+ # Create DP table: dp[i, w] = max value using first i items with capacity w
38+ dp <- matrix (0 , nrow = n + 1 , ncol = capacity + 1 )
39+
40+ # Fill DP table
41+ for (i in 1 : n ) {
42+ for (w in 0 : capacity ) {
43+ # Don't include item i
44+ dp [i + 1 , w + 1 ] <- dp [i , w + 1 ]
45+
46+ # Include item i (if it fits)
47+ if (weights [i ] < = w ) {
48+ include_value <- values [i ] + dp [i , w - weights [i ] + 1 ]
49+ dp [i + 1 , w + 1 ] <- max(dp [i + 1 , w + 1 ], include_value )
50+ }
51+ }
52+ }
53+
54+ # Backtrack to find selected items
55+ selected <- c()
56+ i <- n
57+ w <- capacity
58+
59+ while (i > 0 && w > 0 ) {
60+ # If value came from including item i
61+ if (dp [i + 1 , w + 1 ] != dp [i , w + 1 ]) {
62+ selected <- c(i , selected )
63+ w <- w - weights [i ]
64+ }
65+ i <- i - 1
66+ }
67+
68+ return (list (
69+ max_value = dp [n + 1 , capacity + 1 ],
70+ selected_items = selected ,
71+ dp_table = dp
72+ ))
73+ }
74+
75+ # Space-optimized version using only 1D array
76+ knapsack_01_optimized <- function (weights , values , capacity ) {
77+ # ' Space optimized 0/1 Knapsack using 1D array
78+ # ' @return: Maximum total value
79+
80+ n <- length(values )
81+
82+ if (n == 0 || capacity == 0 ) {
83+ return (0 )
84+ }
85+
86+ dp <- rep(0 , capacity + 1 )
87+
88+ # Process each item
89+ for (i in 1 : n ) {
90+ # Traverse from right to left to avoid overwriting needed values
91+ for (w in capacity : weights [i ]) {
92+ if (weights [i ] < = w ) {
93+ dp [w + 1 ] <- max(dp [w + 1 ], values [i ] + dp [w - weights [i ] + 1 ])
94+ }
95+ }
96+ }
97+
98+ return (dp [capacity + 1 ])
99+ }
100+
101+ # Helper function to print DP table
102+ print_knapsack_dp <- function (dp_table , weights , values , capacity ) {
103+ cat(" DP Table for 0/1 Knapsack:\n " )
104+ cat(" Weights:" , paste(weights , collapse = " , " ), " \n " )
105+ cat(" Values :" , paste(values , collapse = " , " ), " \n " )
106+ cat(" Capacity:" , capacity , " \n\n " )
107+
108+ # Print capacity headers
109+ cat(" " )
110+ cat(paste(sprintf(" %3d" , 0 : capacity ), collapse = " " ))
111+ cat(" \n " )
112+ cat(paste(rep(" -" , 8 + 4 * (capacity + 1 )), collapse = " " ), " \n " )
113+
114+ for (i in 1 : nrow(dp_table )) {
115+ cat(sprintf(" Item %2d | " , i - 1 ))
116+ cat(paste(sprintf(" %3d" , dp_table [i , ]), collapse = " " ))
117+ cat(" \n " )
118+ }
119+ cat(" \n " )
120+ }
121+
122+ # ===========================
123+ # Example Usage & Testing
124+ # ===========================
125+ cat(" === 0/1 Knapsack Problem (Dynamic Programming) ===\n\n " )
126+
127+ # Test 1: Basic Example
128+ weights <- c(1 , 3 , 4 , 5 )
129+ values <- c(1 , 4 , 5 , 7 )
130+ capacity <- 7
131+
132+ cat(" Test 1: Basic Example\n " )
133+ cat(" Weights:" , paste(weights , collapse = " , " ), " \n " )
134+ cat(" Values :" , paste(values , collapse = " , " ), " \n " )
135+ cat(" Capacity:" , capacity , " \n\n " )
136+
137+ result <- knapsack_01(weights , values , capacity )
138+ print_knapsack_dp(result $ dp_table , weights , values , capacity )
139+ cat(" Maximum Value:" , result $ max_value , " \n " )
140+ cat(" Selected Item Indices:" , paste(result $ selected_items , collapse = " , " ), " \n " )
141+ cat(" Total Weight:" , sum(weights [result $ selected_items ]), " \n " )
142+ cat(" Total Value:" , sum(values [result $ selected_items ]), " \n\n " )
143+
144+ # Test 2: Space Optimized Example
145+ cat(" Test 2: Space Optimized Version\n " )
146+ max_val_opt <- knapsack_01_optimized(weights , values , capacity )
147+ cat(" Maximum Value (Optimized):" , max_val_opt , " \n " )
148+ cat(" Verification: Both methods match:" , result $ max_value == max_val_opt , " \n\n " )
149+
150+ # Test 3: Larger Dataset
151+ cat(" Test 3: Larger Dataset\n " )
152+ set.seed(42 )
153+ weights <- sample(1 : 15 , 10 )
154+ values <- sample(10 : 100 , 10 )
155+ capacity <- 35
156+
157+ cat(" Weights:" , paste(weights , collapse = " , " ), " \n " )
158+ cat(" Values :" , paste(values , collapse = " , " ), " \n " )
159+ cat(" Capacity:" , capacity , " \n\n " )
160+
161+ large_result <- knapsack_01(weights , values , capacity )
162+ cat(" Maximum Value:" , large_result $ max_value , " \n " )
163+ cat(" Selected Items:" , paste(large_result $ selected_items , collapse = " , " ), " \n " )
164+ cat(" Total Weight:" , sum(weights [large_result $ selected_items ]), " \n\n " )
165+
166+ # Test 4: Edge Cases
167+ cat(" Test 4: Edge Cases\n " )
168+ cat(" Empty items:" , knapsack_01(c(), c(), 10 )$ max_value , " \n " )
169+ cat(" Zero capacity:" , knapsack_01(weights , values , 0 )$ max_value , " \n " )
170+ cat(" Single item fits:" , knapsack_01(c(5 ), c(10 ), 10 )$ max_value , " \n " )
171+ cat(" Single item doesn't fit:" , knapsack_01(c(10 ), c(10 ), 5 )$ max_value , " \n\n " )
172+
173+ # Test 5: Performance Check
174+ cat(" Test 5: Performance Comparison (n=100)\n " )
175+ n <- 100
176+ weights <- sample(1 : 15 , n , replace = TRUE )
177+ values <- sample(10 : 100 , n , replace = TRUE )
178+ capacity <- 200
179+
180+ start_time <- Sys.time()
181+ res_std <- knapsack_01_optimized(weights , values , capacity )
182+ std_time <- as.numeric(Sys.time() - start_time , units = " secs" )
183+
184+ cat(" Optimized DP result:" , res_std , " \n " )
185+ cat(" Time taken:" , sprintf(" %.4f sec" , std_time ), " \n " )
186+
187+ # Verify correctness
188+ cat(" \n Verifying correctness with full DP:\n " )
189+ start_time <- Sys.time()
190+ res_full <- knapsack_01(weights , values , capacity )
191+ full_time <- as.numeric(Sys.time() - start_time , units = " secs" )
192+ cat(" Full DP result:" , res_full $ max_value , " \n " )
193+ cat(" Time taken:" , sprintf(" %.4f sec" , full_time ), " \n " )
194+ cat(" Results match:" , res_std == res_full $ max_value , " \n " )
0 commit comments