微看背包问题(下)

前言

接着上篇,接着总结。

二、完全背包及其解法

2.1 问题描述

完全背包问题和01背包问题框架很像,都是从一批物品中获取一些物品,这些物品的重量有一定的限制(不超过W),求的是哪种选择可以得到最大的Value。 唯一的不同点就在于完全背包中每种物品可以选择任意次(01背包每种物品只能是0或者1次)。

正式的描述如下图:
在这里插入图片描述
在这里插入图片描述
 

2.2 解法

关于递归搜索的解法这里就不说了,和01解法类似,稍有不同的就是如果背包当前剩余的W还可以装下一次目前的物品,那就继续尝试装。

下面主要介绍完全背包的DP解法。

2.2.1 未优化的DP解法

01背包问题中的重复子问题和最优子结构性质和01问题也类似,这里也就不说了。 有了01背包的基础,这里应该可以推出其状态定义和其转移方程。

在这里插入图片描述
哎,有点回眸一笑,似曾相识的感觉?
再把01背包问题的状态转移方程拿过来康康。

在这里插入图片描述

对,对于当前物品,选了之后还可不可以重复选就体现在这儿了。

还不懂,有点绕人?

动手画个状态矩阵推推。
在这里插入图片描述
还不懂?

enen…, 那就看看其他的资料吧。 这里推荐参考【1】。
 

有了上述的动态方程。 代码部分就很简单了。


/*
 *@description 用DP解决完全背包问题
 *@ dp[i][j] : 前i个物品中挑选出总重量不超过j时的总价值的最大值
 *
*/

int ComPacketProblemByDp(){

     vector<vector<int>> dp(n+1,vector<int>(W+1,0));

     for(int i = 1;i<=n;++i){

        for(int j = 0;j<=W;++j){
            if(j < weight[i-1]){
                dp[i][j] = dp[i-1][j];
            }else{
                dp[i][j] = max(dp[i-1][j],dp[i][j-weight[i-1]]+value[i-1]);     //DP递推公式
            }
        }
     }
    return dp[n][W];

}

note:注意这里的下标区别。
 

2.2.2 状态压缩的DP解法

如果观察状态上述的状态转移矩阵的话,可以发现,每个dp[i+1][j]其实只用到了上面一层的数据(以前的状态),所以可以进行状态压缩,把二维状态压缩为一维的。

代码如下所示:

/*
 *@description 用DP解决完全背包问题,这里用了空间压缩,把二维dp压缩成了一维dp
 *@dp[i][j] : 前i个物品中挑选出总重量不超过j时的总价值的最大值
 *@

*/
int ComPacketProblemByDp1(){
    vector<int> dp(W+1,0);
    for(int i = 1;i<=n;++i){

        for(int j = weight[i-1];j<=W;++j){

            dp[j] = max(dp[j],dp[j-weight[i-1]]+value[i-1]);
        }
    }
    return dp[W];
}

 

三、总结

好了,终于到了激动人心的总结时刻了。

背包问题是动态规划中的经典问题,在学习背包问题的过程中,有了一些关于思考,罗列如下
(1)、对于动态规划来说,熟悉的题我们可能很快就能知道用动态规划进行解题。不熟悉的题,我觉得还是需要利用动态规划的本质,即利用动态规划本身的特点(重复子问题+最优子结构)来进行分析,看其是否可以重复利用以前的状态。

(2)、有人说,动态规划本质上是一种自带裁剪的搜索方法,我觉得有点道理。 有些题目可能有多个变量(比如说背包问题中的价值和重量),这种带多个变量的搜索问题(可以使用动态规划解题),有一个解题方向是控制变量,即控制其中的一个变量,让另一个变量“飞舞”。

(3)、还有些时候,可以从结果来找解题方式。 即最终的结果就那么几种,那么我们就可以遍历这几种状况,来判断是否可行。 背包问题的解法中有点这么个意思(最终背包里的W就那么几种情况)

动态规划的水很深,我刚学会狗刨,还得下水继续练啊。
在这里插入图片描述

参考

【1】、《挑战程序设计》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值