zoukankan      html  css  js  c++  java
  • 浅谈背包

    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)的单调队列优化,然而...我还不会...

  • 相关阅读:
    vim delete
    npm ERR! network connect ETIMEDOUT
    在 ubuntu 14.04 Unity 中清除和关闭 Totem 播放记录
    ubuntu 14.04 上 jvpn 使用说明
    LWP::Protocol::https not installed
    perl 安装模块
    触摸屏工作方式
    如何检测死锁并快速定位死锁位置
    如何用 yum 的一个包替换另一个包
    shell 中 here documemt << 与 <<- 的区别
  • 原文地址:https://www.cnblogs.com/NLDQY/p/10851461.html
Copyright © 2011-2022 走看看