for(int i = 1; i <= n; i++){ cin >> v >> w; for(int j = v;j <= m; j++){//这里j=v,是因为要保证j-v>=0 f[j] = max(f[j], f[j - v] + w); } } /*上一篇代码中,解释过,逆序是为了保证更新当前状态时,用到的状态是上一轮的状态,保证每个物品只有一次或零次; 在这里,因为每个物品可以取任意多次,所以不再强求用上一轮的状态,即本轮放过的物品,在后面还可以再放;*/
多重背包I
每个物品最多取 s 次($O(n^3)$)
二维写法 for(int i = 1; i <= n; i ++){ cin >> v >> w >> s; for(int j = 0; j <= m; j ++){ for(int k = 0; k <= s && k * v <= j; k ++){ f[i][j] = max(f[i][j], f[i - 1][j - v * k] + w * k); // k = 0 已经包含了f [ i ] [ j ] = f [ i - 1 ] [ j ] 也就是不选 i 这个操作, } } }
一维写法 for(int i = 1; i <= n; i ++){ cin >> v >> w >> s; for(int j = m; j >= v; j --){ for(int k = 0; k <= s && k * v <= j; k ++){ f[j] = max(f[j], f[j - v * k] + w * k); } } }
二进制优化 int cnt = 0; for(int i = 1; i <= n; i ++ ){ int a, b, s; cin >> a >> b >> s; int k = 1; while(k <= s){ //二进制分组转化成01背包 cnt ++ ; v[cnt] = a * k; w[cnt] = b * k; s -= k; k *= 2; } if(s > 0){ cnt ++ ; v[cnt] = a * s; w[cnt] = b * s; } } n = cnt; for(int i = 1; i <= n; i ++ ){ for(int j = m; j >= v[i]; j -- ){ f[j] = max(f[j], f[j - v[i]] + w[i]); } }
分组背包
每组物品有若干个,同一组内的物品最多只能选一个。
for(int i = 1; i <= n; i ++ ){ cin >> s[i]; for(int j = 0; j < s[i]; j ++ ){ cin >> v[i][j] >> w[i][j]; } }
for(int i = 1; i <= n; i ++ ){//01背包类似 for(int j = m; j >= 0; j -- ){ for(int k = 0; k < s[i]; k ++ ){ if(j >= v[i][k])f[j] = max(f[j], f[j - v[i][k]] + w[i][k]); } } }