背包问题

  1. //! Solves the knapsack problem
  2. use std::cmp::max;
  3. /// knapsack_table(w, weights, values) returns the knapsack table (`n`, `m`) with maximum values, where `n` is number of items
  4. ///
  5. /// Arguments:
  6. /// * `w` - knapsack capacity
  7. /// * `weights` - set of weights for each item
  8. /// * `values` - set of values for each item
  9. fn knapsack_table(w: &usize, weights: &[usize], values: &[usize]) -> Vec<Vec<usize>> {
  10. // Initialize `n` - number of items
  11. let n: usize = weights.len();
  12. // Initialize `m`
  13. // m[i, w] - the maximum value that can be attained with weight less that or equal to `w` using items up to `i`
  14. let mut m: Vec<Vec<usize>> = vec![vec![0; w + 1]; n + 1];
  15. for i in 0..=n {
  16. for j in 0..=*w {
  17. // m[i, j] compiled according to the following rule:
  18. if i == 0 || j == 0 {
  19. m[i][j] = 0;
  20. } else if weights[i - 1] <= j {
  21. // If `i` is in the knapsack
  22. // Then m[i, j] is equal to the maximum value of the knapsack,
  23. // where the weight `j` is reduced by the weight of the `i-th` item and the set of admissible items plus the value `k`
  24. m[i][j] = max(values[i - 1] + m[i - 1][j - weights[i - 1]], m[i - 1][j]);
  25. } else {
  26. // If the item `i` did not get into the knapsack
  27. // Then m[i, j] is equal to the maximum cost of a knapsack with the same capacity and a set of admissible items
  28. m[i][j] = m[i - 1][j]
  29. }
  30. }
  31. }
  32. m
  33. }
  34. /// knapsack_items(weights, m, i, j) returns the indices of the items of the optimal knapsack (from 1 to `n`)
  35. ///
  36. /// Arguments:
  37. /// * `weights` - set of weights for each item
  38. /// * `m` - knapsack table with maximum values
  39. /// * `i` - include items 1 through `i` in knapsack (for the initial value, use `n`)
  40. /// * `j` - maximum weight of the knapsack
  41. fn knapsack_items(weights: &[usize], m: &[Vec<usize>], i: usize, j: usize) -> Vec<usize> {
  42. if i == 0 {
  43. return vec![];
  44. }
  45. if m[i][j] > m[i - 1][j] {
  46. let mut knap: Vec<usize> = knapsack_items(weights, m, i - 1, j - weights[i - 1]);
  47. knap.push(i);
  48. knap
  49. } else {
  50. knapsack_items(weights, m, i - 1, j)
  51. }
  52. }
  53. /// knapsack(w, weights, values) returns the tuple where first value is `optimal profit`,
  54. /// second value is `knapsack optimal weight` and the last value is `indices of items`, that we got (from 1 to `n`)
  55. ///
  56. /// Arguments:
  57. /// * `w` - knapsack capacity
  58. /// * `weights` - set of weights for each item
  59. /// * `values` - set of values for each item
  60. ///
  61. /// Complexity
  62. /// - time complexity: O(nw),
  63. /// - space complexity: O(nw),
  64. ///
  65. /// where `n` and `w` are `number of items` and `knapsack capacity`
  66. pub fn knapsack(w: usize, weights: Vec<usize>, values: Vec<usize>) -> (usize, usize, Vec<usize>) {
  67. // Checks if the number of items in the list of weights is the same as the number of items in the list of values
  68. assert_eq!(weights.len(), values.len(), "Number of items in the list of weights doesn't match the number of items in the list of values!");
  69. // Initialize `n` - number of items
  70. let n: usize = weights.len();
  71. // Find the knapsack table
  72. let m: Vec<Vec<usize>> = knapsack_table(&w, &weights, &values);
  73. // Find the indices of the items
  74. let items: Vec<usize> = knapsack_items(&weights, &m, n, w);
  75. // Find the total weight of optimal knapsack
  76. let mut total_weight: usize = 0;
  77. for i in items.iter() {
  78. total_weight += weights[i - 1];
  79. }
  80. // Return result
  81. (m[n][w], total_weight, items)
  82. }
  83. #[cfg(test)]
  84. mod tests {
  85. // Took test datasets from https://people.sc.fsu.edu/~jburkardt/datasets/bin_packing/bin_packing.html
  86. use super::*;
  87. #[test]
  88. fn test_p02() {
  89. assert_eq!(
  90. (51, 26, vec![2, 3, 4]),
  91. knapsack(26, vec![12, 7, 11, 8, 9], vec![24, 13, 23, 15, 16])
  92. );
  93. }
  94. #[test]
  95. fn test_p04() {
  96. assert_eq!(
  97. (150, 190, vec![1, 2, 5]),
  98. knapsack(
  99. 190,
  100. vec![56, 59, 80, 64, 75, 17],
  101. vec![50, 50, 64, 46, 50, 5]
  102. )
  103. );
  104. }
  105. #[test]
  106. fn test_p01() {
  107. assert_eq!(
  108. (309, 165, vec![1, 2, 3, 4, 6]),
  109. knapsack(
  110. 165,
  111. vec![23, 31, 29, 44, 53, 38, 63, 85, 89, 82],
  112. vec![92, 57, 49, 68, 60, 43, 67, 84, 87, 72]
  113. )
  114. );
  115. }
  116. #[test]
  117. fn test_p06() {
  118. assert_eq!(
  119. (1735, 169, vec![2, 4, 7]),
  120. knapsack(
  121. 170,
  122. vec![41, 50, 49, 59, 55, 57, 60],
  123. vec![442, 525, 511, 593, 546, 564, 617]
  124. )
  125. );
  126. }
  127. #[test]
  128. fn test_p07() {
  129. assert_eq!(
  130. (1458, 749, vec![1, 3, 5, 7, 8, 9, 14, 15]),
  131. knapsack(
  132. 750,
  133. vec![70, 73, 77, 80, 82, 87, 90, 94, 98, 106, 110, 113, 115, 118, 120],
  134. vec![135, 139, 149, 150, 156, 163, 173, 184, 192, 201, 210, 214, 221, 229, 240]
  135. )
  136. );
  137. }
  138. }