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 背包,