问题:二维费用\(01\)背包问题
题目描述
有 \(n\) 件物品 和 一个容量为 \(V\) 的背包,背包最大承重是 \(M\)
每件物品只能 用一次,第 \(i\) 件物品的 体积 是 \(v_i\),重量 是 \(m_i\),价值 是 \(w_i\)
求解一个选物品的 方案,使得 总体积 不超过 \(V\),总重量 不超过 \(M\) 的,且 总价值 最大
分析
每件物品只能 用一次 因此是个 01背包模型
费用一共有两个,一个是 体积,一个是 重量,因此是个 01背包二维费用问题
本题是一道裸题,直接上 闫氏DP分析法
闫氏DP分析法
初始状态:f[0][0][0]
目标状态:f[n][V][M]
一、三维数组解朴素解法
#include <bits/stdc++.h>
using namespace std;
const int N = 1010;
const int M = 110;
int n;//n个物品
int V;//包的体积上限
int Z;//包的重量上限
int v1[N];//体积
int v2[N];//重量
int w[N];//价值
int f[N][M][M];//三维的dp数组,描述前i个物品,体积j,重量k时的最大价值
//问题:二维费用的01背包问题[三维数组解法]
/**
状态转移方程:
(1)当剩余的空间j不能装下当前物品i,即j<v1[i]时不能选择i物品。
f[i,j,k]=f[i−1,j−vi,k−mi]+wi
(2)当剩余的重量k不能装下当前物品i,即k<v2[i]时不有选择i物品。
f[i,j,k]=f[i−1,j−vi,k−mi]+wi
(3)当j>=v1[i]&&k>=v2[i]时,可以选择要i,还是不要i。
f[i,j,k]=max(f[i−1,j,k],f[i−1,j−vi,k−mi]+wi)
*/
/**
4 5 6
1 2 3
2 4 4
3 4 5
4 5 6
答案:8
*/
int main() {
cin >> n >> V >> Z;
//体积,重量,价值
for (int i = 1; i <= n; i++) cin >> v1[i] >> v2[i] >> w[i];
//遍历每一个物品
for (int i = 1; i <= n; i++)
for (int j = 0; j <= V; j++)//体积
for (int k = 0; k <= Z; k++) //重量
//第i个物品不能要
if (j < v1[i] || k < v2[i]) f[i][j][k] = f[i - 1][j][k];
//第i个物品可以要,还要继续讨论要还是不要
else f[i][j][k] = max(f[i - 1][j - v1[i]][k - v2[i]] + w[i], f[i - 1][j][k]);
//输出
printf("%d", f[n][V][Z]);
return 0;
}
二、二维数组空间优化解法
#include <bits/stdc++.h>
using namespace std;
const int N = 1010;
const int M = 110;
int n;//n个物品
int V;//体积上限
int Z;//重量上限
int v1[N];//每个物品的体积
int v2[N];//每个物品的重量
int w[N];//每个物品的价值
int f[M][M];//二维的dp数组,描述前i个物品
signed main() {
cin >> n >> V >> Z;
//体积,重量,价值
for (int i = 1; i <= n; i++) cin >> v1[i] >> v2[i] >> w[i];
//遍历每一个物品
for (int i = 1; i <= n; i++)
for (int j = V; j >= v1[i]; j--) //由大到小遍历每一个体积
for (int k = Z; k >= v2[i]; k--) //由大到小遍历每一个重量
f[j][k] = max(f[j - v1[i]][k - v2[i]] + w[i], f[j][k]);//动态转移方程,01 背包的思路
//输出
printf("%d", f[V][Z]);
return 0;
}