题目大意:
有 $n$ 个物体 第 $i$ 个物体的体积为 $wi$ 价值为 $vi$ 背包容积为 $W$ 求所有挑选方案中价值总和的最大值
解法1:
针对每个物品是否放入背包进行搜索
时间复杂度:$O(2^n)$
代码:
#include <bits/stdc++.h> using namespace std; const int maxn = 1e5 + 10; int n, W; int w[maxn], v[maxn]; int rec(int i, int j) { int res; if(i == n) res = 0; else if (j < w[i]) res = rec(i + 1, j); else res = max(rec(i + 1, j), rec(i + 1, j - w[i]) + v[i]); return res; } void solve() { printf("%d ", rec(0, W)); } int main() { scanf("%d%d", &n, &W); for(int i = 0; i < n; i ++) scanf("%d%d", &w[i], &v[i]); solve(); return 0; }
解法2:
记忆化搜索,把第一次计算结果存到 $dp$ 数组中,第二次之后如果有同样的 $i, j$ 直接返回
时间复杂度:$O(n * W)$
代码:
#include <bits/stdc++.h> using namespace std; int n, W; int w[11111], v[11111]; int dp[11111][11111]; int rec(int i, int j) { if(dp[i][j] >= 0) return dp[i][j]; int res; if(i == n) res = 0; else if(j < w[i]) res = rec(i + 1, j); else res = max(rec(i + 1, j), rec(i + 1, j - w[i]) + v[i]); return dp[i][j] = res; } void solve() { memset(dp, -1, sizeof(dp)); printf("%d ", rec(0, W)); } int main() { scanf("%d%d", &n, &W); for(int i = 0; i < n; i ++) scanf("%d%d", &w[i], &v[i]); solve(); return 0; }
解法3:
dfs
时间复杂度:$O(2^n)$
代码:
#include <bits/stdc++.h> using namespace std; int n, W; int w[11111], v[11111]; int dfs(int i, int j, int sum) { int res; if(i == n) res = sum; else if(j < w[i]) res = dfs(i + 1, j, sum); else res = max(dfs(i + 1, j, sum), dfs(i + 1, j - w[i], sum + v[i])); return res; } int main() { scanf("%d%d", &n, &W); for(int i = 0; i < n; i ++) scanf("%d%d", &w[i], &v[i]); int num = dfs(0, W, 0); printf("%d ", num); return 0; }
解法4:
动态规划 不写递归函数,直接用递推式把各项的值计算出来(如果多组输入 $dp$ 需要初始化)
时间复杂度:$O(n * W)$
代码1:
#include <bits/stdc++.h> using namespace std; int n, W; int w[11111], v[11111]; int dp[11111][11111]; void solve() { for(int i = n - 1; i >= 0; i --) { for(int j = 0; j <= W; j ++) { if(j < w[i]) dp[i][j] = dp[i + 1][j]; else dp[i][j] = max(dp[i + 1][j], dp[i + 1][j - w[i]] + v[i]); } } printf("%d ", dp[0][W]); } int main() { scanf("%d%d", &n, &W); for(int i = 0; i < n; i ++) scanf("%d%d", &w[i], &v[i]); solve(); return 0; }
代码2:
#include <bits/stdc++.h> using namespace std; int n, W; int w[11111], v[11111]; int dp[11111][11111]; void solve() { for(int i = 0; i < n; i ++) { for(int j = 0; j <= W; j ++) { if(j < w[i]) dp[i + 1][j] = dp[i][j]; else dp[i + 1][j] = max(dp[i][j], dp[i][j - w[i]] + v[i]); } } printf("%d ", dp[n][W]); } int main() { scanf("%d%d", &n, &W); for(int i = 0; i < n; i ++) scanf("%d%d", &w[i], &v[i]); solve(); return 0; }
代码3:
#include <bits/stdc++.h> using namespace std; int n, W; int w[11111], v[11111]; int dp[11111][11111]; void solve() { for(int i = 0; i < n; i ++) { for(int j = 0; j <= W; j ++) { dp[i + 1][j] = max(dp[i][j], dp[i + 1][j]); if(j + w[i] <= W) dp[i + 1][j + w[i]] = max(dp[i + 1][j + w[i]], dp[i][j] + v[i]); } } printf("%d ", dp[n][W]); } int main() { scanf("%d%d", &n, &W); for(int i = 0; i < n; i ++) scanf("%d%d", &w[i], &v[i]); solve(); return 0; }