0-1背包问题
问题描述:有个容量为m的背包和n∈[1, 100]个物品,每个物品的重量为w[i]∈[1, 100],价格为p[i]∈[1, 100],问如何装入物品,使得在不超过背包容量的情况下,使得装下的物品的价格最大?
这题有三种解法,咱们先介绍动态规划的解法。
构造一个一维数组f[10005],f[i]表示背包容量为i时,背包里的物品价格的最大值
于是我们有递推式f[i] = max( f[i], f[i - w] + p);
动态规划
采用自顶而下的遍历
#include <bits/stdc++.h> using namespace std; int f[10005]; int main() { int w[105], p[105], n, m; while(~scanf("%d%d", &n, &m) && n) { memset(w, 0, sizeof(w)); memset(p, 0, sizeof(p)); memset(f, 0, sizeof(f)); for(int i = 0;i < n; ++i) scanf("%d%d", &w[i], &p[i]); for(int i = 0;i < n; ++i) for(int j = m;j >= w[i]; --j) f[j] = max(f[j], f[j - w[i]] + p[i]); printf("%d\n", f[m]); } return 0; }
第二种是用递归法,跟动态规划相似的思路。
递归法
也是自顶而下的。
#include <bits/stdc++.h> using namespace std; int n, w[105], p[105]; void solve(int index, int free_space) { if(index < 0 || free_space <= 0) return 0; int ret = solve(index - 1, free_space); if(w[index]<=free_space) ret=max(ret,solve(index-1,free_space-w[index])); return ret; } int main() { while(~scanf("%d%d", &n, &m)) { memset(w, 0, sizeof(w)); memset(p, 0, sizeof(p)); for(int i = 0;i < n; ++i) scanf("%d%d", &w[i], &p[i]); printf("%d\n", solve(n - 1, m)); } }
优化下递归就成了记忆化搜索。
记忆化搜索
#include <bits/stdc++.h> using namespace std; int n, w[105], p[105], me[105][105]; void solve(int index, int free_space) { if(index < 0 || free_space <= 0) return 0; if(me[index][free_space]) return me[index][free_space]; int ret = solve(index - 1, free_space); if(w[index]<=free_space) ret=max(ret,solve(index-1,free_space-w[index])); me[index][free_space] = ret; return ret; } int main() { while(~scanf("%d%d", &n, &m)) { memset(w, 0, sizeof(w)); memset(p, 0, sizeof(p)); memset(me, 0, sizeof(me)); for(int i = 0;i < n; ++i) scanf("%d%d", &w[i], &p[i]); printf("%d\n", solve(n - 1, m)); } }
来源:https://www.cnblogs.com/xdaniel/p/12260206.html