昨天搞完了0/1背包问题今天又学习了完全背包问题再次做一个总结 完全背包问题题想较于0/1背包问题区别就在于 0/1背包中的物品只能使用一次而完全背包问题的物品可以使用任意次 那么解题的方法也与0/1背包问题十分相似当我们在装入一个物品之后随着背包的体积继续变大我们可以继续往背包里装东西 所以转移方程相较于0/1背包发生了变化dp[i][j]=max(dp[i][j],dp[i][j-vol[i]]+value[i]]这个转移方程不难理解 其实完全背包相比的是当放入第k个编号为i物品的包的价值和没有放入第k个编号为i物品(为什么是第k个因为在前面可能已经放入了k-1个编号为i的物品) 大概的思路就是这样下面我们引入代码
int dp[1000]={0};
int dp1[1000][1000]={0};
int n,v;
struct BONE
{
int val;
int vol;
}bone[1000];//利用结构体记录每一个物品的价值和体积
void slove2()
{
for(int i=1;i<=n;i++)
{
for(int j=1;j<=v;j++)
{
dp1[i][j]=dp1[i-1][j];//先继承上一个
if(j>=bone[i].vol)
dp1[i][j]=max(dp1[i][j],dp1[i][j-bone[i].vol]+bone[i].val);//转移方程
}
}
}
常规的模板就是这样 但是我们的目的只是为了最终的那个体积的包 所以这些中间变量完全可以不用储存 那么我们可以利用滚动数组 但是滚动数组的用法和0/1背包问题不同 0/1背包问题的每一层的状态都是由上一层体积小于当前体积的状态推断出来的(详细的见我昨天写的博客0/1背包问题)所以应当使用倒序而我们在完全背包问题的转移方程里已经看到当前状态是由同一层的推断而出的所以我们应当使用正序代码如下
void slove1()//滚动数组
{
for(int i=1;i<=n;i++)
{
for(int j=bone[i].vol;j<=v;j++)
{
dp[j]=max(dp[j],dp[j-bone[i].vol]+bone[i].val);//相较于0/1背包完全背包题目这里我们需要比叫的是i而不是i-1而用滚动数组的时候我们需要正序因为一个物品可能不只加一次
}
}
}
学习算法是一个持久的过程 我们都应当沉下心更努力下去