优先理解01背包:
推导:我们列举一下更新次序的内部关系: f[i , j ] = max( f[i-1,j] , f[i-1,j-v]+w , f[i-1,j-2*v]+2*w , f[i-1,j-3*v]+3*w , .....) f[i , j-v]= max( f[i-1,j-v] , f[i-1,j-2*v] + w , f[i-1,j-3*v]+2*w , .....) 由上两式,可得出如下递推关系: f[i][j]=max(f[i,j-v]+w , f[i-1][j])
1.01背包和完全背包核心代码其实只有一句不同(注意下标)f[i][j] = max(f[i][j],f[i-1][j-v[i]]+w[i]); //01背包 f[i][j] = max(f[i][j],f[i][j-v[i]]+w[i]); //完全背包问题
为什么完全背包变成了 i 呢,因为 每个物品都是可以随便选的,不像01背包只能选一次。
2.同样优化:
核心代码:for(int i = 1 ; i<=n ;i++) for(int j = v[i] ; j<=m ;j++)//注意了,这里的j是从小到大枚举,和01背包不一样 { f[j] = max(f[j],f[j-v[i]]+w[i]); }
为什么从前往后枚举呢,因为与01背包反过来,要保证是当前 i 层更新的,而不是第 i-1 层更新过来的。
点击跳转例题
代码:
#include<bits/stdc++.h> using namespace std; const int MAXN = 10000; int v[MAXN]; // 体积 int w[MAXN]; // 价值 int f[MAXN][MAXN]; // f[i][j], j体积下前i个物品的最大价值 int main() { int n; int m; // 背包体积 cin >> n >> m; for(int i = 1; i <= n; i++) cin >> v[i] >> w[i]; f[0][0] = 0; for(int i = 1; i <= n; i++) for(int j = 0; j <= m; j++) { f[i][j] = f[i - 1][j]; // 不选第i个物品//集合一定存在; //再次更新集合,看是否有更大的解; if(j >= v[i]) // 可以选择第i个物品,状态方程见上面推导 f[i][j] = max(f[i][j], f[i][j - v[i]] + w[i]); } cout << f[n][m] << endl; return 0; }
完全背包详解--模板
最新推荐文章于 2024-05-30 20:15:33 发布