zoukankan      html  css  js  c++  java
  • 0/1背包

    0/1背包的问题模型如下:

      给定N个物品,其中第i个物品的体积为V,价值为Wi 。有一容积为M的背包,要选择一些物品放入背包,使物品体积不超过M的前提下,物品的价值总和最大。

    dp[i][j]表示从前i个物品中选出了总体积为j的物品放入背包,物品的最大价值。即我们很容易得出解决的代码:

    memset(dp,0,sizeof(dp));
        dp[0][0]=0;
        for(int i=1;i<=n;i++){
            for(int j=0;j<=m;j++)
                dp[i][j]=dp[i-1][j];
            for(int j=v[i];j<=m;j++)
                dp[i][j]=max(dp[i][j],dp[i-1][j-v[i]]+w[i]);
        }

    根据上面的代码 我们可以看出 状态方程的推导只和当前状态以及上一状态有关。所以我们可以用滚动数组优化

    memset(dp,0,sizeof(dp));
        dp[0][0]=0;
        for(int i=1;i<=n;i++){
            for(int j=0;j<=m;j++)
                dp[i&1][j]=dp[(i-1)&1][j];
            for(int j=v[i];j<=m;j++)
                dp[i&1][j]=max(dp[i&1][j],dp[(i-1)&1][j-v[i]]+w[i]);
        }

    这里我们只要2*m的空间即可

    其实进一步分析代码,在每个阶段的开始,我们实际上只是执行了一次从dp[i-1][]到dp[i][]的一次拷贝,也就是说我们可以进一步省略掉dp数组的第一维

    即dp[j]表示背包中放入总体积为j的最大价值

    memset(dp,0,sizeof(dp));
        dp[0]=0;
        for(int i=1;i<=n;i++){
            for(int j=m;j>=v[i];j--)
                dp[j]=max(dp[j],dp[j-v[i]]+w[i]);
        }

    我们应该可以注意到,我们的第二重循环采用了倒序的方式,这是为了满足0/1背包问题中每个物品是唯一的,只能放入一次的要求

     

  • 相关阅读:
    shell if 条件语句实践
    shell函数
    透视财富增长的秘密
    kvm虚拟化实践
    Linux驱动编程--基于I2C子系统的I2C驱动
    Makefile中=、:=、+=、?=的区别
    字符设备驱动结构与开发
    驱动分类
    为什么ARM的frq中断的处理速度比较快
    Linux设备驱动01
  • 原文地址:https://www.cnblogs.com/wmj6/p/10387746.html
Copyright © 2011-2022 走看看