【题目来源】AcWing 2. 01背包问题
【解题思路】
每一个物品都有自己的价值和体积,我们可以用结构体数组进行存储:
struct res{
int v, w;
} q[N];
正确输入数据:
const int N = 1050;
struct res{
int v, w;
} q[N];
int n, V;
int main(){
cin >> n >> V;
for(int i = 1; i <=n ; i ++) cin >> q[i].v >> q[i].w;
return 0;
}
动态规划思想:
int dp[N][N]; //可能出现的最大价值为全部装下,即为1000×1000,int类型数组即可
//dp[i][j],代表当背包空间为 j 时,我面前有前 i 个物品,能够装入的最大价值
dp[i][j]分为两种情况,在dp[i - 1][j]的基础上:
①不装入第 i 个物品,dp[i - 1][j];
②装入第 i 个物品,要求当前的背包空间不小于q[i].v,dp[i - 1][j - q[i].v] + q[i].w;
这两种情况,取最大值,即状态转移方程
dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - q[i].v] + q[i].w);
memset(dp, 0, sizeof dp); //dp数组初始化为全0或者将dp数组定义为全局变量
for(int i = 1; i <= n; i ++){ //遍历前 n 个物品
for(int j = 0; j <= V; j ++){ //遍历0~V的空间
dp[i][j] = dp[i - 1][j];
if(j >= q[i].v){
dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - q[i].v] + q[i].w);
}
}
}
最后答案即为,当背包空间为 V 时,我面前有前 n 个物品,能够装入的最大价值。
cout << dp[n][V];
时间复杂度: N 2 N^2 N2 + + + N N N = = = O ( O( O( n 2 n^2 n2 ) ) ) = = = 100 0 2 1000^2 10002 = = = 1 0 6 10^6 106, 1000 m s 1000ms 1000ms能过;
空间复杂度: 1000 × 1000 × i n t 1000×1000×int 1000×1000×int = = = 1 0 6 10^6 106 × × × 4 B y t e 4Byte 4Byte ≈ ≈ ≈ 3.81 M B 3.81MB 3.81MB,能过。
优化:我们发现dp[i][j]的值取决于dp[i - 1][j]或dp[i - 1][j - q[i].v],即上一行同一列或上一行前列,因此可将二维数组dp[i][j]优化为dp[j],数组前面的值不变并且会决定后面的值,所以应该从后往前遍历。
for(int i = 1; i <= n; i ++){
for(int j = V; j >= q[i].v; j --){
dp[j] = max(dp[j], dp[j - q[i].v] + q[i].w); //1000×int
}
}
cout << dp[V];