多重背包问题入门+dp储存空间优化
这个入门知识点对应洛谷通天背包问题。
下面看下问题:
AC代码如下:
#include<bits/stdc++.h>
using namespace std;
int weight[2000],price[2000],s[2000][200000],number1[2000];
int dp[2000];
int main()
{
int m,n,number=0,t=0;
cin>>m>>n;
for(int i=1;i<=n;i++)
{
cin>>weight[i]>>price[i]>>number;
t=max(t,number);
number1[number]++;
s[number][number1[number]]=i;
}
for(int i=1;i<=t;i++)//总共有t组 从第一组开始
{
for(int j=m;j>=0;j--)//背包容积剩余 j
{
for(int c=1;c<=number1[i];c++)//这组里面有多少个元素
{
if(j>=weight[s[i][c]])
{
dp[j]=max(dp[j],dp[j-weight[s[i][c]]]+price[s[i][c]]);
}
}
}
}
cout<<dp[m]<<endl;
return 0;
}
多重背包和01背包的区别就是01背包的物体只是单个的,但多重背包问题的物品是集合的形式。打个比方:01背包面对的物品是砖石或砖头,但多重背包问题面对的物品是一个砖石和砖头混在一起的物品,如果要选择价值最大的,就要对这个混合物进行挑选。
将题目的意思转述一下:你有一个容积为V的背包,有N个箱子,每个箱子里有m件物品,现在从每个箱子里取物品,且每个箱子最多只能拿走一件物品,问你能拿走的最大价值物品为多少。
分析下问题:看到这个东西很快能想到01背包的dp,但有一处不同,即01背包中的一个物品变成了一个箱子。所以我们要在原本的模板上加一重循环,表示遍历箱子中的每一个物品。
分析一下代码:
for(int i=1;i<=t;i++)//总共有t组 从第一组开始
{
for(int j=m;j>=0;j--)//背包容积剩余 j
{
for(int c=1;c<=number1[i];c++)//这组里面有多少个元素
{
if(j>=weight[s[i][c]])
{
dp[j]=max(dp[j],dp[j-weight[s[i][c]]]+price[s[i][c]]);
}
}
}
}
和01背包相似,我们要确定当前状态的最值,即当在前 i 个箱子里取物体,背包容积为 j 时的最值。
那么我们要进行对比的是:前i-1个箱子取物体,背包容积为j时的最值。
AC代码里我是用一维数组来进行存储空间的优化的,所以就聊聊为什么可以这样写吧!
首先:不难发现,每一次比较都是通过与上一次数据进行比较,所以只用把现在的数据覆盖在原有的数据之上就可以实现二维数组的功能。
但使用这种存储空间的优化要注意:一定从j=m 开始递减,这样才可以模拟覆盖过程,实现对比功能。
上面的话要听的活一点,不要什么题都重最大开始递减,关键还是要实现对比和覆盖的过程。