完全背包时间优化:
状态转移方程:dp[i][j] = max(dp[i-1][j], dp[i][j - c[i]] + w[i])
有以下的内容,状态转移与k无关了,状态转移的时间复杂度从O(m)变成了O(1)
对于第i个物品,其实有两种选择,一个都不放,至少放一个。
一个都不放,就是前i-1种物品放满一个容量为j的背包,是dp[i-1][j]
至少放一个的话,我们尝试在"前i个物品放满一个容量为j的背包",拿到一个物品,即前i种物品放满一个容量为j-c[i]的背包,这个时候便是dp[i][j-c[i]] + w[i]
代码分析,核心代码
function KnapsackComplete(n, m, c[n+1], w[n+1], dp[n+1][m+1])
dp[0][0] = init
for i->(1, m)
dp[0][i] = inf
for i-> (1,n)
for j-> (0, c[i]-1)
dp[i][j] = dp[i-1][j]
for j->(c[i], m)
dp[i][j] = opt(dp[i-1][j], dp[i][j-c[i]]+w[i])
代码练习 1 对应蓝桥云课 小明的背包2 见下
cpp
#include <iostream>
using namespace std;
#define maxn 1001
#define maxv 1001
#define inf -1
#define init 0
#define vType int
vType opt(vType a, vType b){
if(a == inf) return b;
if(b == inf) return a;
return a>b ? a:b;
}
void KnapsackComplete(int n, int V, int w[maxn], vType v[maxv], vType dp[maxn][maxv]){
for(int i=1; i<=V; ++i){
dp[0][i] = inf;
}
dp[0][0] = init;
for(int i=1; i<=n; ++i){
for(int j=0; j<w[i]; ++j){
dp[i][j] = dp[i-1][j];
}
for(int j=w[i]; j<=V; ++j){
dp[i][j] = max(dp[i-1][j], dp[i][j-w[i]] + v[i]);
}
}
}
int n, V;
int w[maxn];
vType v[maxn];
vType dp[maxn][maxv];
int main()
{
cin >> n >> V;
for(int i=1; i<=n; ++i){
cin >> w[i] >> v[i];
}
KnapsackComplete(n, V, w, v, dp);
int ans = inf;
for(int i=0; i <= V; ++i){
ans = max(ans, dp[n][i]);
}
cout << ans << endl;
// 请在此输入您的代码
return 0;
}
完全背包空间优化,公式见下
dp[j] = max(dp[j], dp[j - c[i]] + w[i])
代码分析:
核心代码,
function KnapsackComplete(n, m, c[n+1], w[n+1], dp[m+1])
dp[0] = init
for i->(1, m)
dp[i] = inf
for i-> (1,n)
for j-> (c[i], m)
dp[j] = opt(dp[j], dp[j-c[i]]+w[i])
代码练习 1 对应蓝桥云课 小明的背包2 代码见下
cpp
#include <iostream>
using namespace std;
#define maxn 1001
#define maxv 1001
#define inf -1
#define init 0
#define vType int
vType opt(vType a, vType b){
if(a == inf) return b;
if(b == inf) return a;
return a>b ? a:b;
}
void KnapsackComplete(int n, int V, int w[maxn], vType v[maxv], vType dp[maxv]){
dp[0] = init;
for(int i=1; i<=V; ++i){
dp[i] = inf;
}
for(int i=1; i<=n; ++i){
for(int j=w[i]; j<=V; ++j){
dp[j] = opt(dp[j], dp[j-w[i]]+v[i]);
}
}
}
int n, V;
int w[maxn];
vType v[maxn];
vType dp[maxv];
int main()
{
cin >> n >> V;
for(int i=1; i<=n; ++i){
cin >> w[i] >> v[i];
}
KnapsackComplete(n, V, w, v, dp);
int ans = inf;
for(int i=0; i <= V; ++i){
ans = max(ans, dp[i]);
}
cout << ans << endl;
// 请在此输入您的代码
return 0;
}
代码练习2 对应力扣硬币 代码见下
cpp
#define maxn 5
#define maxv 1000001
#define inf 0
#define init 1
#define vType int
vType opt(vType a, vType b){
if(a == inf) return b;
if(b == inf) return a;
return (a+b)%1000000007;
}
void KnapsackComplete(int n, int V, int w[maxn], vType v[maxv], vType dp[maxv]){
dp[0] = init;
for(int i=1; i<=V; ++i){
dp[i] = inf;
}
for(int i=1; i<=n; ++i){
for(int j=w[i]; j<=V; ++j){
dp[j] = opt(dp[j], dp[j-w[i]]+v[i]);
}
}
}
int n, V;
int w[maxn] = {-1, 25, 10, 5, 1};
vType v[maxn] = {-1, 0, 0, 0, 0};
vType dp[maxv];
class Solution {
public:
int waysToChange(int n) {
KnapsackComplete(4, n, w, v, dp);
return dp[n];
}
};