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+ dp <- matrix (0 , nrow = n + 1 , ncol = capacity + 1 )
28+
29+ # Fill DP table
30+ for (i in 2 : (n + 1 )) {
31+ for (w in 0 : capacity ) {
32+ if (weights [i - 1 ] < = w ) {
33+ include <- values [i - 1 ] + dp [i - 1 , w - weights [i - 1 ] + 1 ]
34+ exclude <- dp [i - 1 , w + 1 ]
35+ dp [i , w + 1 ] <- max(include , exclude )
36+ } else {
37+ dp [i , w + 1 ] <- dp [i - 1 , w + 1 ]
38+ }
39+ }
40+ }
41+
42+ # Backtrack to find selected items
43+ res_value <- dp [n + 1 , capacity + 1 ]
44+ selected <- c()
45+ w <- capacity
46+
47+ for (i in n : 1 ) {
48+ if (res_value < = 0 ) break
49+ if (res_value == dp [i , w + 1 ]) next
50+
51+ # Item i is included
52+ selected <- c(i , selected )
53+ res_value <- res_value - values [i ]
54+ w <- w - weights [i ]
55+ }
56+
57+ return (list (
58+ max_value = dp [n + 1 , capacity + 1 ],
59+ selected_items = selected ,
60+ dp_table = dp
61+ ))
62+ }
63+
64+ # Space-optimized version using only 1D array
65+ knapsack_01_optimized <- function (weights , values , capacity ) {
66+ # ' Space optimized 0/1 Knapsack using 1D array
67+ # ' @return: Maximum total value
68+
69+ n <- length(values )
70+ dp <- rep(0 , capacity + 1 )
71+
72+ for (i in 1 : n ) {
73+ for (w in capacity : weights [i ]) {
74+ dp [w + 1 ] <- max(dp [w + 1 ], values [i ] + dp [w - weights [i ] + 1 ])
75+ }
76+ }
77+
78+ return (dp [capacity + 1 ])
79+ }
80+
81+ # Helper function to print DP table
82+ print_knapsack_dp <- function (dp_table , weights , values , capacity ) {
83+ cat(" DP Table for 0/1 Knapsack:\n " )
84+ cat(" Weights:" , paste(weights , collapse = " , " ), " \n " )
85+ cat(" Values :" , paste(values , collapse = " , " ), " \n " )
86+ cat(" Capacity:" , capacity , " \n\n " )
87+
88+ for (i in 1 : nrow(dp_table )) {
89+ cat(sprintf(" Item %2d | " , i - 1 ))
90+ cat(paste(sprintf(" %3d" , dp_table [i , ]), collapse = " " ))
91+ cat(" \n " )
92+ }
93+ cat(" \n " )
94+ }
95+
96+ # ===========================
97+ # Example Usage & Testing
98+ # ===========================
99+ cat(" === 0/1 Knapsack Problem (Dynamic Programming) ===\n\n " )
100+
101+ # Test 1: Basic Example
102+ weights <- c(1 , 3 , 4 , 5 )
103+ values <- c(1 , 4 , 5 , 7 )
104+ capacity <- 7
105+
106+ cat(" Test 1: Basic Example\n " )
107+ cat(" Weights:" , paste(weights , collapse = " , " ), " \n " )
108+ cat(" Values :" , paste(values , collapse = " , " ), " \n " )
109+ cat(" Capacity:" , capacity , " \n\n " )
110+
111+ result <- knapsack_01(weights , values , capacity )
112+ print_knapsack_dp(result $ dp_table , weights , values , capacity )
113+ cat(" Maximum Value:" , result $ max_value , " \n " )
114+ cat(" Selected Item Indices:" , paste(result $ selected_items , collapse = " , " ), " \n\n " )
115+
116+ # Test 2: Space Optimized Example
117+ cat(" Test 2: Space Optimized Version\n " )
118+ max_val_opt <- knapsack_01_optimized(weights , values , capacity )
119+ cat(" Maximum Value (Optimized):" , max_val_opt , " \n\n " )
120+
121+ # Test 3: Larger Dataset
122+ cat(" Test 3: Larger Dataset\n " )
123+ set.seed(42 )
124+ weights <- sample(1 : 15 , 10 )
125+ values <- sample(10 : 100 , 10 )
126+ capacity <- 35
127+
128+ cat(" Weights:" , paste(weights , collapse = " , " ), " \n " )
129+ cat(" Values :" , paste(values , collapse = " , " ), " \n " )
130+ cat(" Capacity:" , capacity , " \n\n " )
131+
132+ large_result <- knapsack_01(weights , values , capacity )
133+ cat(" Maximum Value:" , large_result $ max_value , " \n " )
134+ cat(" Selected Items:" , paste(large_result $ selected_items , collapse = " , " ), " \n\n " )
135+
136+ # Test 4: Edge Cases
137+ cat(" Test 4: Edge Cases\n " )
138+ cat(" Empty items:" , knapsack_01(c(), c(), 10 )$ max_value , " \n " )
139+ cat(" Zero capacity:" , knapsack_01(weights , values , 0 )$ max_value , " \n " )
140+ cat(" Single item fits:" , knapsack_01(c(5 ), c(10 ), 10 )$ max_value , " \n " )
141+ cat(" Single item doesn't fit:" , knapsack_01(c(10 ), c(10 ), 5 )$ max_value , " \n\n " )
142+
143+ # Test 5: Performance Check
144+ cat(" Test 5: Performance Comparison (n=100)\n " )
145+ n <- 100
146+ weights <- sample(1 : 15 , n , replace = TRUE )
147+ values <- sample(10 : 100 , n , replace = TRUE )
148+ capacity <- 200
149+
150+ start_time <- Sys.time()
151+ res_std <- knapsack_01_optimized(weights , values , capacity )
152+ std_time <- as.numeric(Sys.time() - start_time , units = " secs" )
153+
154+ cat(" Optimized DP result:" , res_std , " \n " )
155+ cat(" Time taken:" , sprintf(" %.4f sec" , std_time ), " \n " )
0 commit comments