01背包 1维 (滚动数组)

这里先说一下二维的。

///01背包
///设物品有n件物品,背包容量为w
int w[];     ///代表n件物品的价值
int pw[];    ///代表n件物品各占的容量

int f[n+50][w+50];   ///最优解二维数组
///f[i][j]数组 代表存i件物品在容量为j的背包中得到的价值

void package_01(){
    for(int i=0;i<=n;i++) f[i][0]=0;
    for(int j=0;j<=c;j++) f[0][j]=0;    ///初始化,       ///若要求恰好装满,除这两个初始化外,其他值全部赋值为 -0x3f3f3f3f,(这样能够保证最后恰好装满)
                                                         ///

    for(int i=1;i<=n;i++){      ///有点枚举的感觉,枚举n件物品
        for(int j=pw[i];j<=c;j++){  ///与上同理
            if(f[i-1][j-pw[i]]+w[i]>f[i-1][j])  ///i-1件物品放入j-pw[i]容量的价值+w[i]的价值(即为放) 与 i-1件物品放入j容量(即为不放) 的所得价值比较
                f[i][j]=f[i-1][j-pw[i]]+w[i];
            else f[i][j]=f[i-1][j];
        }
    }
    printf("%d\n",f[n][w]);     ///f[n][w]即为最优解
}

二维的状态转移方程

f[i][j] = max \left\{\begin{matrix} f[i-1][j-pw[i]] + w[i] \\ f[i-1][j] \end{matrix}\right. 

很显然,f[i][*]  只与  f[j-1][*] 的状态有关  所以这里可以有空间上的优化。

先看代码:

memset(dp, 0, sizeof(dp));
for(int i=0; i=pw[i]; j--){
        dp[j] = max(dp[j], dp[j-pw[i]]+w[i])
    }
}

对于外层的循环,每进行一次,dp[] 保存的状态都还是  i - 1 时候的dp[] ,所以在第二层循环使用的时候就相当于使用的是

dp[i - 1][j - pw[i]] + w[i] 与 dp[i-1][j] ..

并且,状态转移方程,每一次推导 dp[i][j] 是通过 dp[i-1][j-w[i]] 来推导的,所以一维数组中j的扫描顺序应该从大到小(c 到 0),否者前一次循环保存下来的值将会被修改,从而造成错误。

 

你可能感兴趣的:(#,dp)