背包问题
完全背包问题
有一个背包体积为V,有n个物品,均有(V,W)
两个属性,代表着他们的体积以及价值,现在所有的物品无限取用,求背包总和能够达到最大价值的物品取用方案。
递推式的推导
N ( i , V ) N(i,V) N(i,V)代表着取用i个物品下,总体积不超过V的最大价值组合。
那么如何推导出这个公式呢,因为可以用的物品是无限个物品所以相应的公式可以设置为 N ( i , V ) = m a x ( N ( i − 1 , V ) , N ( i − 1 , V − v ) + w , N ( i − 2 , V − 2 v ) + 2 w , . . . ) N(i,V) = max(N(i-1,V),N(i-1,V-v)+w,N(i-2,V-2v)+2w,...) N(i,V)=max(N(i−1,V),N(i−1,V−v)+w,N(i−2,V−2v)+2w,...)
这个公式或许一开始难以理解,但是我们可以将其看成是由初始状态一层一层递推而来的,除了N(i-1,V)
外,还包含着前面物品采用多次的情况。
那么我们也可以将 V V V替换 V − v V-v V−v写出等价的式子 N ( i , V − v ) = m a x ( N ( i − 1 , V − v ) , N ( i − 1 , V − 2 v ) + w , N ( i − 2 , V − 3 v ) + 2 w N(i,V-v)=max(N(i-1,V-v),N(i-1,V-2v)+w,N(i-2,V-3v)+2w N(i,V−v)=max(N(i−1,V−v),N(i−1,V−2v)+w,N(i−2,V−3v)+2w
可知二式 N ( i , V − v ) + w N(i,V-v)+w N(i,V−v)+w即可与一式的 N ( i − 1 , V − v ) . . . . N(i-1,V-v).... N(i−1,V−v)....等价,便可得到递推公式
N ( i , V ) = m a x ( N ( i − 1 , V ) , N ( i , V − v ) + w N(i,V)=max(N(i-1,V),N(i,V-v)+w N(i,V)=max(N(i−1,V),N(i,V−v)+w
如此一来便可写出完全背包问题的代码:下面代码仅仅展现了思路
// input the data and assign the array
int n,v; // n -> the numebr of item , V -> the volume of bag
int dp[n][b];
int item[n]; // item have the property v w
// algorithm main
for(int i=1;i<=n;i++)
{
for(int j=1;j<=v;j++)
{
dp[i][j] = dp[i-1][j];
if (v-j>=0)
dp[i][j] = max(dp[i][j], dp[i-1][j-item[i].v]+item[i].w);
}
}
cout<<dp[n][v];
最终我们实现的代码如下,在3. 完全背包问题 - AcWing题库 中Ac成功.
#include <iostream>
#include <vector>
using namespace std;
struct Item {
int weight;
int value;
};
int knapsack(int n, int v, vector<Item>& items) {
vector<vector<int>> dp(n + 1, vector<int>(v + 1, 0));
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= v; j++) {
dp[i][j] = dp[i - 1][j];
if (j - items[i - 1].weight >= 0) {
dp[i][j] = max(dp[i][j], dp[i][j - items[i - 1].weight] + items[i - 1].value);
}
}
}
return dp[n][v];
}
int main() {
int n, v;
cin >> n >> v; // 输入物品数量和背包容量
vector<Item> items(n);
for (int i = 0; i < n; i++) {
cin >> items[i].weight >> items[i].value; // 输入每个物品的重量和价值
}
int result = knapsack(n, v, items);
cout << result << endl;
return 0;
}