dp 背包问题 模板

  https://www.kancloud.cn/kancloud/pack/70131   //巨佬讲解

01背包

1.1
题目 有N 件物品和一个容量为V 的背包。放入第i 件物品耗费的费用是Ci,得到的 价值是Wi。求解将哪些物品装入背包可使价值总和最大。 1.2 基本思路 这是最基础的背包问题,特点是:每种物品仅有一件,可以选择放或不放。用子问题定义状态:即F[i,v] 表示前i件物品恰放入一个容量为v

的背包可以获得的最大价值。(i为第i件商品,v为限制条件)则其状态转移方程便是:
    F[i,v]
=max{F[i-1,v],F[i-1;v-Ci]+Wi}

这个方程非常重要,基本上所有跟背包相关的问题的方程都是由它衍生出来的。所以有必要将它详细解释一下:“将前i件物品放入容量为v 的背包中”这个子问题,

若只考虑第i 件物品的策略(放或不放),那么就可以转化为一个只和前i-1 件物品相关的问题。 如果不放第i件物品,==>“前i-1 件物品放入容量为v 的背包中”,价值为F[i-1,v]; 如果放第i件物品,那么问题就转化为“前i-1 件物品放入剩下的容量为v-Ci 的背包中”,此时能获得的最大价值就是F[i-1,v-Ci] 再加上通过放入第i 件物品获得的价值Wi。
无优化代码
1
for(int i=1;i<=n;i++){ 2 for(int c=0;c<=m;c++){ 3 f[i][c]=f[i-1][c]; 4 if(c>=w[i]){ 5 f[i][c]=max(f[i][c],f[i-1][c-w[i]]+v[i]); 6 } 7 } 8 }
一维数组优化
1
for(int i=1;i<=n;i++){ 2 for(int c=m;c>=0;c--){ 3 if(c>=w[i]) 4 f[c]=max(f[c],f[c-w[i]]+v[i]); 5 } 6 }
1 for(int i=1;i<=n;i++){
2     sumw+=w[i];
3     bound=max(m-sumw,w[i]);
4     for(int c=m;c>=bound;c--){
5         if(c>=w[i])
6         f[c]=max(f[c],f[c-w[i]]+v[i]);
7     }
8 }
常数优化
1
for(int i=1;i<=n;i++){ 2 sumw+=w[i]; 3 bound=max(m-sumw,w[i]); 4 for(int c=m;c>=bound;c--){ 5 if(c>=w[i]) 6 f[c]=max(f[c],f[c-w[i]]+v[i]); 7 } 8 }
完全背包问题
完全背包:有N种物品和一个容量为V的背包,每种物品都有无限件可用。第i种物品的费用是c[i],价值是w[i]。

求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。 


 differ:01背包和完全背包

 01背包反向遍历,这样更新就不会影响前面的。

 完全背包正向遍历,更新会改变前面,所以也就可出现多次存放的了。
 
  
1 for(int i=1;i<=n;i++){
2     for(int c=0;c<=m;c++){
3         if(c>=w[i])
4         f[c]=max(f[c],f[c-w[i]]+v[i]);
5     }
6 }


Eg:洛谷 P2722 score inflation https://www.luogu.org/problem/P2722

 AC代码

1
#include<iostream> 2 3 using namespace std; 4 5 int m,n,s[10010],t[10010],dp[10010]; 6 7 void f(){ 8 for(int i=0;i<n;i++){ 9 for(int j=t[i];j<=m;j++){ 10 dp[j]=max(dp[j],dp[j-t[i]]+s[i]); 11 } 12 } 13 cout<<dp[m]; 14 } 15 16 int main(){ 17 cin>>m>>n; 18 for(int i=0;i<n;i++){ 19 cin>>s[i]>>t[i]; //每个"种类"题目的分数和耗时 20 } 21 f(); 22 return 0; 23 } 24 25 26 // 限制条件 : t
 
  

 



多重背包问题
多重背包:有N种物品和一个容量为V的背包。第i种物品最多有n[i]件可用,每件费用是c[i],价值是w[i]。

求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且价值总和最大。
 
  

 

 
  
 1 for(int i=1;i<=n;i++){
 2     if(w[i]*a[i]>m){
 3         for(int c=0;c<=m;c++){
 4             if(c>=w[i]){
 5                  f[c]=max(f[c],f[c-w[i]]+v[i]);
 6             }
 7         }
 8     }
 9     else {
10          k=1;amount=a[i];
11          while(k<amount){
12              for(int c=k*w[i];c>=0;c--){
13                  if(c>=w[i])
14                  f[c]=max(f[c],f[c-w[i]]+k*v[i]);
15              }
16              amount-=k;
17              k<<=1;
18          }  
19          for(int c=amount*w[i];c>=0;c--){
20              f[c]=max(f[c],f[c-w[i]]+amount*v[i]);
21          }
22     } 
23 }                 
 
  

 

有依赖的背包问题

def:这种背包问题的物品间存在某种“依赖”的关系。也就是说,物品i 依赖于物品j,表示若选物品i,则必须选物品j。
为了简化起见,我们先设没有某个物品既依赖于别的物品,又被别的物品所依赖;另外,没有某件物品同时依赖多件物品。

经典例题:NOIP2006 中“金明的预算方案”

算法

  我们可以想到,对于第k个物品组中的物品,所有费用相同的物品只留一个价值最大的,不影响结果。所以,可以对主件k 的“附件集合”先进行一次01 背包,



 






 

转载于:https://www.cnblogs.com/jjjjjjy/p/11338231.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值