浅谈背包

01背包:

问题:有N件物品和一个容量为V的背包。第i件物品的体积是w[i],价值是v[i]。求解将哪些物品装入背包可使这些物品的重量总和不超过背包容量,且价值总和最大。

思路:对每种物品我们可以选择用或不用,则有状态转移方程\(f[i][j]=max(f[i-1][j-w[i]]+v[i],f[i][j])\)

Code:

for(int i=1;i<=n;i++)
	for(int j=1;j<=V;j++)
		if(j>=w[i]) f[i][j]=max(f[i-1][j-w[i]]+v[i],f[i][j])

事实上我们发现这个方程内当前状态的转移之和上一个物品有关,则我们可以考虑优化空间

我们倒序dp,数组变成一维,\(f[j]=max(f[j-w[i]]+v[i],f[j])\),倒序dp的原因是为了不覆盖上次的值

Code:

for(int i=1;i<=n;i++)
	for(int j=V;j>=1;j--)
		if(j>=w[i]) f[j]=max(f[j-w[i]]+v[i],f[j]);

完全背包:

问题:有N件物品和一个容量为V的背包。第i件物品的体积是w[i],价值是v[i],每件物品可以用无限次。求解将哪些物品装入背包可使这些物品的重量总和不超过背包容量,且价值总和最大。

思路:状态转移方程不变,但由于每件物品可以用无数次,则不用考虑上件物品的影响,正序dp即可

Code:

for(int i=1;i<=n;i++)	
    for(int j=1;j<=V;j++)
        if(j>=w[i]) f[j]=max(f[j-w[i]]+v[i],f[j]);

多重背包:

问题:有N件物品和一个容量为V的背包。第i件物品的体积是w[i],价值是v[i],每件物品可以用u次。求解将哪些物品装入背包可使这些物品的重量总和不超过背包容量,且价值总和最大。

思路:可以看做是可取u个的01背包来做

Code:

for(int i=1;i<=n;i++)	
    for(int j=V;j>=1;j--)
        for(int k=1;k<=u;k++)
            if(j>=k*w[i]) f[j]=max(f[j-k*w[i]]+k*v[i],f[j]);

事实上我们可以进行优化,可以将u进行二进制分解,然后再来dp,时间复杂度O(VN log u)

Code:

int b=1;
while(u){
    if(u&1) a[++cnt]=b;
    b<<=1;u>>=1;
}int t=0;
for(int i=1;i<=n;i++)
    for(int j=1;j<=cnt;j++)
        w0[++t]=w[i]*a[j],v0[t]=v[i]*a[j];
for(int i=1;i<=t;i++)
    for(int j=V;j>=1;j--)
        if(j>=w0[i]) f[j]=max(f[j-w0[i]]+v0[i],f[j]);

然而还有O(VN)的单调队列优化,然而...我还不会...

posted @ 2019-05-12 11:18  DQY_dqy  阅读(130)  评论(0编辑  收藏  举报