• 0-1背包


    有n种物品,第i种物品的体积为V[i],重量为W[i],选一些物品放到容量为c的背包里,使得背包内的物品在总体积不超过C的前提下重量尽量大。

    用d(i,j)表示当前处于第i层,背包的剩余重量为j,通俗点说就是把  i  i+1  i+2 .....n 个物品装到容量为j的背包中的最大总重量。

    所以我们得到的状态转移方程为:

        

                        d(i+1,j)                           ( 0=<j<v[i])     

     d(i,j)=       max( d(i+1,j)  ,  d(i+1,j-v[i])+w[i]  )           (j>v[i])

     最终的答案为  d(1,c)

    #include<iostream>
    #define MAX 100
    using namespace std;
    int main(){
        int n,c;
        int d[MAX][MAX];
        int v[MAX],w[MAX];
        while(cin>>n>>c){
            memset(d,0,sizeof(d));
            for(int i=1;i<=n;i++)
                cin>>v[i]>>w[i];
            for(int i=n;i>=1;i--){
                for(int j=0;j<=c;j++){
                    d[i][j]=(i==n ? 0: d[i+1][j])  ;
                    if(j>=v[i])
                        d[i][j]=max(d[i][j],d[i+1][j-v[i]]+w[i]);
                }
            }
            cout<<d[1][c]<<endl;
        }
        return 0;
    }

    聪明的读者也许看出来了,还有另外一种对称的状态的定义:

    用f(i,j) 表示把前i个物品装到容量为j的背包中的最大重量,其转移方程也不难得出

    f(i,j)=max(f(i-1,j),f(i-1,j-v[i])+w[i])

    最终的答案为  f(n,c);

    于是上面的代码就可以改写为

                   for(int i=1;i<=n;i++){
    			for(int j=0;j<=c;j++){
    				f[i][j]=(i==1?0:f[i-1][j]);
    				(if j>=v[i] )f[i][j]=max(f[i][j],f[i-1][j-v[i]]+w[i]);
    			}
    		}
    

      

    看上去两种方式是完全对称的,但是还是有细微差别的,新的允许边读边写,而不必把w,v保存下来。

        for(int i=1;i<=n;i++){
                for(int j=0;j<=c;j++){
                    cin>>v>>w;
                    f[i][j]=(i==1?0:f[i-1][j]);
                    f[i][j]=max(f[i][j],f[i-1][j-v]+w);
                }
            }

    更为奇妙的是还可以把数组f变成一维:

    for(int i=1;i<=n;i++){
                cin>>v>>w;
                for(int j=c;j<=0;j--){
                    if(j>=v){
                     f[j]=max(f[j],f[j-v]+w);
                    }
                }
            }

    值得注意的是j一定要逆序。

    如果是顺序的话,在一次i的循环中就会利用前面的结果,从而导致不是在这一次中放一个物品,而是多个的假象,读者可以自行试试。

    在递推法中,如果计算顺序很特殊,而且计算新状态所用到的原状态不多的话,可以尝试用滚动数组来减少内存开销。

  • 相关阅读:
    电脑华硕A455L系列,机械硬盘换成固态硬盘,光驱位改放机械硬盘
    帮助命令
    文件搜索命令
    命令基本格式及文件处理命令
    Jupyter Notebook出现kernel error情况
    八、数据拟合分析seaborn
    Scrapy中的错误
    (续篇)Selenium 安装配置以及如何解决('chromedriver' executable needs to be in PATH. Please see https://sites.google.com/a/chromium.org/ch)或者(unknown error:cannot find Chrome binary)问题?
    如何安装selenium以及scrapy,最重要的是pip?
    五、SVM推导过程
  • 原文地址:https://www.cnblogs.com/wintersong/p/4960362.html
Copyright © 2020-2023  润新知