C++ 完全背包
完全背包特点:属于线性DP、状态转移方程固定、时间复杂度固定O(nm2 附,这里2是平方)、需要先学习01背包
第一步,状态设计,状态(i,j)表示前i个物品恰好放入容量为j的背包(i属于[0, n],j属于[0, m])。令dp[i][j]表示状态(i, j)下该背包得到的最大价值。
第二步,状态转移方程,dp[i][j] = max(dp[i-1][j-k*c[i]] + k*w[i]) (0 =< k =< j/c[i]),如果“第i个物品不放入容量为j的背包”,那么转态转化为求“前i-1种物品放入容量为j的背包”的问题;由于不放,所以最大价值就等于“前i-1个物品放入容量为j的背包”的最大价值,对应状态转移方程中k=0的情况,即dp[i-1][j]。如果“第i个物品放入容量为j的背包”,那么转态转化为求“前i-1种物品放入容量为j-c[i]*k的背包”的问题;由于不放,所以最大价值就等于“前i-1个物品放入容量为j-c[i]*k的背包”的最大价值加上放入k个第i种物品的价值,即dp[i-1][j-k*c[i]] + k*w[i]。枚举所有满足条件的k就是我们所求的“前i个物品恰好放入容量为j的背包”的最大价值了,dp[i][j] = max([放k个])。
完全背包是01背包的拓展,区别是他可以取0件,1件,,,k件,而01背白只能去0件,1件。如果从转态转移方程出发,可以归纳为以下的方程:
01背包 (0=< k =<1)
完全背包(0=< k =<j)
代码分析:
1 基础常量定义:inf = -1 init = 0
2 最优值定义:
function opt(a, b)
if a == inf
return b
if b == inf
return a
return max(a,b)
3 核心代码
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, m)
dp[i][j] = inf
for k -> (0, j/c[i])
dp[i][j] = opt(dp[i][j], dp[i-1][j - k*c[i]] + k*w[i])
代码练习 1 对应蓝桥云课 小明的背包2 代码见下
#include <iostream>
using namespace std;#define maxn 1001
#define maxv 1001
#define inf -1
#define init 0
#define vType intvType 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<=V; ++j){dp[i][j] = inf;for(int k=0; k<=j/w[i]; ++k){dp[i][j] = opt(dp[i][j], dp[i-1][j - k*w[i]] + k*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;
}