我们之前的那篇文章学习了什么是01背包,01背包的DP二维实现,DP一维实现。在这篇文章中我们学习完全背包问题:
完全背包和01背包的区别在于,01背包每个物品只有一个,所以每个物品只有装和不装两个选择,但是在完全背包中,每个物品数量都是无穷个,所以可以随便选取。即:
有 N 种物品和一个容量为 V 的背包,每种物品都有无限件可用。放入第 i 种物品的费用是 Ci,价值是 Wi。求解:将哪些物品装入背包,可使这些物品的耗费的费用总
和不超过背包容量,且价值总和最大
我们找到的状态转移方程为:
F [i,v] = max { F [i − 1,v − kCi] + kWi | 0 ≤ kCi ≤ v }
我们将上面的k分别选为0 和1,即为我们的01背包的状态转换式。同理,我们的完全背包也可以写为一维数组实现:
F [0...V ] 0
for i = 1 to N
for v = Ci to V
F [v] = max(F [v],F [v − Ci] + Wi)
不知大家注意到没有,在01背包中,我们为了保证F [v] 是由之前的F [i − 1,v − Ci]递推而来,而不是F [i ,v − Ci]递推而来(其实就是防止在背包中多次放入一个物品),我们对于容量v的遍历是从后往前的逆序(详见本文)
但是,在这里,我们是从前往后的顺序,因为没有了物体只有一个的约束:
我们还以采药的题目(5938: 【基础背包入门3】第二次 采药)为例子:
#include <iostream>
using namespace std;
int main()
{
int dp[1002];
int v[120];
int w[120];
int T,M;
while(cin >>T>>M&&T>0&&M>0)
{
for(int i = 1; i<=M; i++)
{
cin>>v[i]>>w[i];
}
for(int j = 0; j<=T; j++)
{
dp[j] = 0;
}
for(int i = 1; i <= M; i++)
{
for(int j = 0; j<=T; j++)
{
if(j>=v[i]&&dp[j]<dp[j-v[i]]+w[i])
{
dp[j] = dp[j-v[i]]+w[i];
}
}
}
cout<<dp[T]<<endl;
}
return 0;
}
所以,在背包中,我们推荐使用一维数组的实现形式,简单又好记
P.S.文章不妥之处还望指正