关键词: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] )