引言——dp里面的背包问题。多重背包是指每个物品有c[i]个数量,如果普通的进行dp,f[i][v]=max{f[i-1][v-k*c[i]]+ k*w[i]|0<=k<=n[i]},那么会TLE(虽说我也不知道到底是多少…dalao们帮忙说下呗),如果将数量进行二进制拆分时,那么时间复杂度会显著减少( QAQ我也不知道是多少啊啊啊orz,跪求大佬)
1.思想。
将一个数二进制拆分后变为2^0+2^1+2^2…+2^k+(num-2^k).
原理:
1、2、4可以组合出所有小于8的数。
1、2、4、8可以组合出所有小于16的数。
……
例如,一个数10,我可以分成1、2、4、3。这样就将原本的10个价值相同的物品转化为价值不同的4个物品了。(时间复杂度–!!)
2.代码。
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<queue>
using namespace std;
inline int read()
{
int p,data=0;
char ch=0;
while((ch!='-')&&ch<'0'||ch>'9') ch=getchar();
if(ch=='-')
{
p=-1;
ch=getchar();
}
else
{
p=1;
}
while(ch>='0'&&ch<='9')
{
data=data*10+ch-'0';
ch=getchar();
}
return data*p;
}
int volume[110];
int val[110];
int ccount[110];
int dp[51000];
int main()
{
memset(dp,0,sizeof(0));
int num,space;
num=read();
space=read();
for(int i=1;i<=num;i++)
{
volume[i]=read();
val[i]=read();
ccount[i]=read();
}
**for(int i=1;i<=num;i++)
{
int d1=1;//d1从1 2 4 8开始枚举,当下一个d1大于剩余物品时,就退出,将剩余物品看成一个物品d2
int d2=ccount[i];
while(d1<d2)
{
for(int j=space;j>=d1*volume[i];j--)
{
dp[j]=max(dp[j],dp[j-d1*volume[i]]+val[i]*d1);
}
d2-=d1;
d1*=2;
}
for(int j=space;j>=d2*volume[i];j--)
{
dp[j]=max(dp[j],dp[j-d2*volume[i]]+val[i]*d2);
}
}**
cout<<dp[space];
return 0;
}