• 浅谈背包


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

  • 相关阅读:
    20210805-接口测试实战(持续更新中···)
    2021-07-06:关于自动化测试
    学习记录-更新时间-2021-04-09
    知识点@解决端口被占用的问题
    PS学习笔记
    JS去掉数组中重复的数
    验证码倒计时
    统计数组中出现最多的字母及次数
    验证码倒计时js
    小兔鲜css
  • 原文地址:https://www.cnblogs.com/NLDQY/p/10851461.html
Copyright © 2020-2023  润新知