背包类问题总结

关键词:0-1背包,完全背包,多重背包及优化

基础DP总结 :  http://www.cnblogs.com/lnu161403214/p/7821417.html

一、0-1背包

题目 : 有N件物品和一个容量为V的背包。第i件物品的重量是w[i],价值是v[i]。求解将哪些物品装入背包可使这些物品的重量总和不超过背包容量,且价值总和最大。

DP求最大价值 :以dp[i][j]表示有i件物品,背包容量为j时所能达到的最大价值,以DP的思想看,与子状态的联系取决于这第i个物品要不要放入背包里,不放的话,dp[i][j]=dp[i-1][j],放的话,由于背包容量还是j,dp[i][j]=dp[i-1][j-w[i]]+v[i]。

因此递推式 : dp[i][j] = max( dp[i-1][j] , dp[i-1][j-w[i]]+v[i] )

两层for循环:

 

for (int i = 1; i <= N; ++i) {
    for (int j = 0; j <= V; ++j) {
        if(j >= w[i]) {
            dp[i][j] = max(dp[i - 1][j - w[i]] + v[i], dp[i - 1][j]);
        }
        else {
            dp[i][j] = dp[i-1][j];
        }
    }
}

 

对于这个,还有个空间上的优化,可以注意到每次都是对i-1的更新,那么直接视作对上一轮的循环的更新不就行了吗,比如直接一个dp[j],每一轮循环更新一次不就是对上一层循环的更新吗。。。当然还有一个细节,就是第二轮循环的顺序,如果还是从小到大的顺序,那么在更新dp[j]之前,dp[j-w[i]]已经在这一轮被更新了,也就是递推式变成了dp[i][j]=dp[i][j-w[i]]+v[i]。。。所以,第二轮顺序要倒着来,这样dp[j]一定是在i-1的状态下更新。

 

for (int i = 1; i <= n; ++i)
    for (int j = v; j >= w[i]; --j)
        dp[j] = max(dp[j - w[i]] + v[i], dp[j]);

 

二、完全背包

题目 : 有N件物品和一个容量为V的背包,每件物品可以取任意次。第i件物品的重量是w[i],价值是v[i]。求解将哪些物品装入背包可使这些物品的重量总和不超过背包容量,且价值总和最大。

递推式 : dp[i][j] = max( dp[i-1][j] , dp[i][j-w[i]]+v[i] ) 

上面已经分析过了,so...

for (int i = 1; i <= n; ++ i)
    for (int j = c[i]; j <= v; ++ j)
        dp[j] = max(dp[j - c[i]] + w[i], dp[j]);

三、多重背包

题目 : 有N件物品和一个容量为V的背包,每件物品可以取k[i]次。第i件物品的重量是w[i],价值是v[i]。求解将哪些物品装入背包可使这些物品的重量总和不超过背包容量,且价值总和最大。

处理 : 1)直接转换成0-1背包问题,比如一个物品转换成k[i]个相同的物品。

 

       时间复杂度 :0( V * ∑k[i] )

    2)二进制优化

     这个思想和(1)相似,只不过比如34个a物品,分成了以下6个物品

    

 

     (注 :1,2,4,8,16,3可以组装出1~34中的任何数的,比如3=1+2,33=2+4+8+16+3)      

     时间复杂度 :0( V * ∑logk[i] )

    推荐个题目 : http://acm.hdu.edu.cn/showproblem.php?pid=1171

posted @ 2017-11-17 17:17  hzhuan  阅读(175)  评论(0编辑  收藏  举报