首先是多重背包问题的朴素版,简单模板
for(int i=1;i<=n;i++)
for(int j=0;j<=m;j++)
{
dp[i][j]=dp[i-1][j];
for(int k=0;k*v[i]<=j&&k<=num[i];k++)
dp[i][j]=max(dp[i][j],dp[i-1][j-k*v[i]]+k*w[i]);
}
下面讲讲如何优化
时间优化
首先前置知识 快速幂
可以知道一个性质 一个数必然可以由若干个2的整数幂组成
那么二进制优化的多重背包问题也是如此
刚开始的前k+1组,人数分别为 1,2,4,8...2^(K+1)
当剩下的人<2^(k+1) 就不能划分了,剩下一组。
所以对于一个数,必然可以划分为如下组
1 , 2, 4, 8 ... 2^k m 每组人数在倍增到不能再增加时停止
划分为了若干组,要选择多少个,都一定可以用这些组人数来表示出来
而如何表示呢
- 如果选择了这组 当前被选择拿的个数+=该组人数
- 如果不选择这组 当前被选择拿的个数不变
分组结束后,其实就是01背包问题啦
#include <iostream>
#include <algorithm>
using namespace std;
const int N=12005;
int v[N],w[N];
int dp[N];
int main()
{
int cnt=0;
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++)
{
int a,b,s;
cin>>a>>b>>s;
int k=1;
while(k<=s)
{
cnt++;
v[cnt]=k*a;
w[cnt]=k*b;
s-=k;
k<<=1;
}
if(s>0)
{
cnt++;
v[cnt]=a*s;
w[cnt]=b*s;
}
}
n=cnt;
for(int i=1;i<=n;i++)
for(int j=m;j>=0;j--)
{
if(j>=v[i])
dp[j]=max(dp[j],dp[j-v[i]]+w[i]);
}
cout<<dp[m];
return 0;
}