|
| 1 | +package algorithms.dynamic |
| 2 | + |
| 3 | +/// Minimal Items Knapsack Problem |
| 4 | +/// Given an array of positive weights and a target weight W, |
| 5 | +/// this function computes the minimum number of items needed to exactly reach weight W using dynamic programming. |
| 6 | +/// Each item may be used at most once. |
| 7 | +/// |
| 8 | +/// dp(x) represents the minimal number of items required to achieve weight x. |
| 9 | +/// - Base case: dp(0) = 0 (no item is needed to achieve weight 0) |
| 10 | +/// - Recurrence: For each item with weight w and for each x from W down to w: |
| 11 | +/// if dp(x - w) is not INF then |
| 12 | +/// dp(x) = min(dp(x), dp(x - w) + 1) |
| 13 | +/// |
| 14 | +/// Time Complexity: O(n * W), where n is the number of items. |
| 15 | +def minimalItems(weights: Array[Int], W: Int): (Int, Array[Int]) = { |
| 16 | + // Define INF as a value greater than any possible number of items (here: W + 1) |
| 17 | + val INF = W + 1 |
| 18 | + // Initialize dp array: dp(x) stores the minimal number of items to reach weight x. |
| 19 | + val dp: Array[Int] = Array.fill(W + 1)(INF) |
| 20 | + dp(0) = 0 |
| 21 | + |
| 22 | + // Process each weight (item) exactly once. |
| 23 | + for (w <- weights) { |
| 24 | + // Iterate backwards to ensure each item is used only once. |
| 25 | + for (x <- W to w by -1) { |
| 26 | + if (dp(x - w) != INF) { |
| 27 | + dp(x) = math.min(dp(x), dp(x - w) + 1) |
| 28 | + } |
| 29 | + } |
| 30 | + } |
| 31 | + |
| 32 | + // If dp(W) is still INF, there is no solution. |
| 33 | + val result = if (dp(W) == INF) -1 else dp(W) |
| 34 | + (result, dp) |
| 35 | +} |
| 36 | + |
| 37 | +@main |
| 38 | +def mainMinimalItems(): Unit = { |
| 39 | + // Example: Items with weights 2, 5, 3, 6 and target weight W = 10. |
| 40 | + val weights: Array[Int] = Array(2, 5, 3, 6) |
| 41 | + val W = 10 |
| 42 | + val (minItems, dp) = minimalItems(weights, W) |
| 43 | + |
| 44 | + if (minItems == -1) |
| 45 | + println(s"Cannot exactly reach weight $W with the given items.") |
| 46 | + else |
| 47 | + println(s"Minimum number of items to exactly reach weight $W: $minItems") |
| 48 | + |
| 49 | + println("DP Array (minimal number of items for each weight):") |
| 50 | + dp.zipWithIndex.foreach { case (items, weight) => |
| 51 | + val info = if (items == W + 1) "not reachable" else items.toString |
| 52 | + println(s"Weight $weight: $info") |
| 53 | + } |
| 54 | +} |
0 commit comments