本文主要以01背包,最长共子序列,最大子数组和等问题讲解动态规划。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
| #include <bits/stdc++.h>
using namespace std;
void knapsackDP(vector<int> &wgt, vector<int> &val, int cap) { int n = wgt.size(); vector<vector<int>> dp(n + 1, vector<int>(cap + 1, 0)); vector<vector<bool>> selected(n + 1, vector<bool>(cap + 1, false)); for (int i = 1; i <= n; i++) { for (int c = 1; c <= cap; c++) { if (wgt[i - 1] > c) { dp[i][c] = dp[i - 1][c]; } else { dp[i][c] = max(dp[i - 1][c], dp[i - 1][c - wgt[i - 1]] + val[i - 1]); if (dp[i][c] == dp[i - 1][c - wgt[i - 1]] + val[i - 1]) { selected[i][c] = true; } } } } cout << dp[n][cap] << endl; vector<int> selectedItems; int i = n, c = cap; while (i > 0 && c > 0) { if (selected[i][c]) { selectedItems.push_back(i - 1); c -= wgt[i - 1]; } i--; } for (int j = selectedItems.size() - 1; j >= 0; j--) { cout << "x" << selectedItems[j] + 1 << " "; } cout << endl;
return; }
int main() { int n; int cap; cin >> n >> cap;
vector<int> wgt(n); vector<int> val(n); for (int i = 0; i < n; i++) { cin >> wgt[i]; } for (int i = 0; i < n; i++) { cin >> val[i]; }
knapsackDP(wgt, val, cap);
return 0; }
|
对于这段代码,在通过一个数据集时,输出为
1 2
| 42 x1 x3 x4 x6 x8 x9 x10
|
然而期望输出为
分析原因,并修改代码
1 2
| 42 x1 x3 x4 x6 x7 x8 x10
|
在你的代码中,当你在追踪选取状态时,可能出现错误。在选取状态更新部分,你使用了:
1 2 3
| if (dp[i][c] == dp[i - 1][c - wgt[i - 1]] + val[i - 1]) { selected[i][c] = true; }
|
这样的判断条件会导致在选择物品 i 时,只能考虑到上一行的状态,而忽略了之前已经选择的物品对当前状态的影响。这就是为什么你的输出结果与期望输出不同的原因。
修改的方法是,在状态转移时,考虑前一次迭代的状态,而不仅仅是上一行的状态。这样可以确保在更新选取状态时,考虑到之前已经选择的物品对当前状态的影响。
下面是修改后的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
| #include <bits/stdc++.h>
using namespace std;
void knapsackDP(vector<int> &wgt, vector<int> &val, int cap) { int n = wgt.size(); vector<vector<int>> dp(n + 1, vector<int>(cap + 1, 0)); vector<vector<bool>> selected(n + 1, vector<bool>(cap + 1, false)); for (int i = 1; i <= n; i++) { for (int c = 1; c <= cap; c++) { if (wgt[i - 1] > c) { dp[i][c] = dp[i - 1][c]; } else { dp[i][c] = max(dp[i - 1][c], dp[i - 1][c - wgt[i - 1]] + val[i - 1]); if (dp[i][c] == dp[i - 1][c]) { selected[i][c] = false; } else { selected[i][c] = true; } } } } cout << dp[n][cap] << endl; vector<int> selectedItems; int i = n, c = cap; while (i > 0 && c > 0) { if (selected[i][c]) { selectedItems.push_back(i - 1); c -= wgt[i - 1]; } i--; } for (int j = selectedItems.size() - 1; j >= 0; j--) { cout << "x" << selectedItems[j] + 1 << " "; } cout << endl;
return; }
int main() { int n; int cap; cin >> n >> cap;
vector<int> wgt(n); vector<int> val(n); for (int i = 0; i < n; i++) { cin >> wgt[i]; } for (int i = 0; i < n; i++) { cin >> val[i]; }
knapsackDP(wgt, val, cap);
return 0; }
|
这样的修改应该会使你的代码输出期望的结果。