1. 程式人生 > 其它 >揹包問題系列(01揹包、完全揹包、多重揹包)

揹包問題系列(01揹包、完全揹包、多重揹包)

揹包問題是一個經典的動態規劃問題,問題可以描述為:給定一組物品,每種物品都有自己的重量和價格,在限定的總重量內,我們如何選擇,才能使得物品的總價格最高。根據給定物品的數量,揹包問題又可分為:

1)每種物品只有一件,即01揹包問題

2)每種物品不限數量,可選取任意數量,即完全揹包問題

3)每種物品的數量已給定,不可超出該數量,即多重揹包問題

揹包問題的重點:

1)編寫狀態轉移方程

2)空間優化

本文參考https://zhuanlan.zhihu.com/p/93857890,使用C++程式碼完成了三種問題的程式碼及空間優化程式碼

  1 #include <iostream>
  2 #include <vector>
  3
using namespace std; 4 5 int max(int a, int b) 6 { 7 return a > b ? a : b; 8 } 9 10 int min(int a, int b) 11 { 12 return a < b ? a : b; 13 } 14 15 // 01揹包問題,n件物品,重量為v 16 int BagProblem_01(const vector<int> &weight, const vector<int> &value, int n, int
v) 17 { 18 // 前i件物品揹包限重為j的情況下的最大值 19 vector<vector<int>> dp(n, vector<int>(v + 1, 0)); 20 21 for (int i = 0; i <= v; i++) 22 { 23 if (i >= weight[0]) 24 { 25 dp[0][i] = value[0]; 26 } 27 } 28 29 for (int i = 1
; i < n; i++) 30 { 31 for (int j = 1; j <= v; j++) 32 { 33 if (j < weight[i]) 34 { 35 dp[i][j] = dp[i - 1][j]; 36 } 37 else 38 { 39 dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]); 40 } 41 } 42 } 43 44 return dp[n - 1][v]; 45 } 46 47 // 01揹包問題--優化空間 48 int BagProblem_01_optimize(const vector<int> &weight, const vector<int> &value, int n, int v) 49 { 50 // 前i件物品揹包限重為j的情況下的最大值 51 vector<int> dp(v + 1, 0); 52 53 for (int i = 0; i <= v; i++) 54 { 55 if (weight[0] > v) 56 { 57 dp[0] = value[0]; 58 } 59 } 60 61 for (int i = 1; i < n; i++) 62 { 63 for (int j = v; j >= weight[i]; j--) // dp[j]是由上一行<=j列推出,j需逆向列舉 64 { 65 dp[j] = max(dp[j], dp [j - weight[i]] + value[i]); 66 } 67 } 68 69 return dp[v]; 70 } 71 72 // 完全揹包問題 73 int BagProblem_complete(const vector<int> &weight, const vector<int> &value, int n, int v) 74 { 75 vector<vector<int>> dp(n, vector<int>(v + 1, 0)); 76 77 for (int j = 0; j <= v; j++) 78 { 79 dp[0][j] = j / weight[0] * value[0]; 80 } 81 82 for (int i = 1; i < n; i++) 83 { 84 for (int j = 0; j <= v; j++) 85 { 86 if (j < weight[i]) 87 { 88 dp[i][j] = dp[i - 1][j]; 89 } 90 else 91 { 92 dp[i][j] = max(dp[i - 1][j], dp[i][j - weight[i]] + value[i]); 93 } 94 } 95 } 96 97 return dp[n - 1][v]; 98 } 99 100 // 完全揹包問題——優化空間 101 int BagProblem_complete_optimize(const vector<int> &weight, const vector<int> &value, int n, int v) 102 { 103 vector<int> dp(v + 1, 0); 104 105 for (int j = 0; j <= v; j++) 106 { 107 dp[j] = j / weight[0] * value[0]; 108 } 109 110 for (int i = 1; i < n; i++) 111 { 112 for (int j = 0; j <= v; j++) // dp[j]是由上一行j列和本行小於j列推出,因此需要正向列舉 113 { 114 if (j >= weight[i]) 115 { 116 dp[j] = max(dp[j], dp[j - weight[i]] + value[i]); 117 } 118 } 119 } 120 121 return dp[v]; 122 } 123 124 // 多重揹包問題 125 int BagProblem_multi(const vector<int> &weight, const vector<int> &value, const vector<int> &nums, int n, int v) 126 { 127 vector<vector<int>> dp(n, vector<int>(v + 1, 0)); 128 129 for (int j = 0; j <= v; j++) 130 { 131 int num = min(j / weight[0], nums[0]); 132 dp[0][j] = num * value[0]; 133 } 134 135 for (int i = 1; i < n; i++) 136 { 137 for (int j = 0; j <= v; j++) 138 { 139 if (j < weight[i]) 140 { 141 dp[i][j] = dp[i - 1][j]; 142 } 143 else 144 { 145 int num = min(j / weight[i], nums[i]); 146 for (int k = 0; k <= num; k++) 147 { 148 dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - k * weight[i]] + k * value[i]); 149 } 150 } 151 } 152 } 153 154 return dp[n - 1][v]; 155 } 156 157 // 多重揹包問題——優化空間 158 int BagProblem_multi_optimize(const vector<int> &weight, const vector<int> &value, const vector<int> &nums, int n, int v) 159 { 160 vector<int> dp(v + 1, 0); 161 162 for (int j = 0; j <= v; j++) 163 { 164 int num = min(j / weight[0], nums[0]); 165 dp[j] = num * value[0]; 166 } 167 168 for (int i = 1; i < n; i++) 169 { 170 for (int j = v; j >= 0; j--) // dp[j]是由上一行<=j列推出,需要逆向列舉 171 { 172 int num = min(j / weight[i], nums[i]); 173 for (int k = 0; k <= num; k++) 174 { 175 if (j < k * weight[i]) 176 continue; 177 dp[j] = max(dp[j], dp[j - k * weight[i]] + k * value[i]); 178 } 179 } 180 } 181 182 return dp[v]; 183 } 184 185 int main() 186 { 187 int v = 10; 188 int n = 5; 189 vector<int> weight{ 2, 2, 4, 6, 3 }; 190 vector<int> value { 1, 3, 3, 5, 6 }; 191 vector<int> nums { 1, 2, 3, 4, 1 }; 192 193 cout << BagProblem_01(weight, value, n, v) << endl; 194 cout << BagProblem_01_optimize(weight, value, n, v) << endl; 195 196 cout << BagProblem_complete(weight, value, n, v) << endl; 197 cout << BagProblem_complete_optimize(weight, value, n, v) << endl; 198 199 cout << BagProblem_multi(weight, value, nums, n, v) << endl; 200 cout << BagProblem_multi_optimize (weight, value, nums, n, v) << endl; 201 202 return 0; 203 }