背包九讲 整理中...
作者:互联网
动态规划问题往往相当让人头疼,学习了Tianyi Cui大佬的背包九讲,做个整理。
一、01背包
题目:(题目取自AcWing,链接https://www.acwing.com/problem/content/2/)
有 N 件物品和一个容量为 V 的背包。放入第 i 件物品耗费的费用是 Ci ,得到的 价值是 Wi。求解将哪些物品装入背包可使价值总和最大。
输入格式 第一行两个整数,N,V,用空格隔开,分别表示物品数量和背包容积。 接下来有 N 行,每行两个整数 vi,wi,用空格隔开,分别表示第 i 件物品的体积和价值。 输出格式 输出一个整数,表示最大价值。
input:
4 5
1 2
2 4
3 4
4 5
output:
8
标准解法:
01背包就是要么装,要么不装,要求不高的题目用深搜回溯也能过了,对数据规模大的需要动态规划求解。
我们用f[i][j]表示前i个物品在背包容量为j下的最大价值,则对每个物品有两种情况,装或不装。若不装很好理解, f[i][j]=f[i-1][j]; 若装, f[i][j]=max(f[i-1][j],f[i-1][j-c[i]]+v[i]); 后一半是背包容量去掉当前物品大小然后加上当前物品价值。这里如果漏写与前一半的比较会出错,漏写往往是因为与回溯剪枝弄混了,这里的状态转移不是装了一定比不装价值大,一定要分清。
1 #include <bits/stdc++.h> 2 using namespace std; 3 #define maxn 1005 4 int f[maxn][maxn];//背包大小为i的最优解; 5 int c[maxn];//费用 6 int v[maxn];//价值 7 int main() 8 { 9 int n,m; 10 cin>>n>>m; 11 for(int i=1; i<=n; i++) 12 cin>>c[i]>>v[i]; 13 for(int i=1; i<=n; i++) 14 for(int j=1; j<=m; j++){ 15 if(j<c[i]) f[i][j]=f[i-1][j]; 16 else f[i][j]=max(f[i-1][j],f[i-1][j-c[i]]+v[i]); 17 } 18 cout<<f[n][m]; 19 return 0; 20 }
空间优化:
注意到标准解法的状态转移方程其实只与前一层的状态有关,由于解法自底向上的特性,我们只保留当前求解的前一层即可.
1 #include <bits/stdc++.h> 2 using namespace std; 3 #define maxn 1005 4 int f[maxn];//背包大小为i的最优解; 5 int c[maxn];//费用 6 int v[maxn];//价值 7 int main() 8 { 9 int n,m; 10 cin>>n>>m; 11 for(int i=1; i<=n; i++) 12 cin>>c[i]>>v[i]; 13 for(int i=1; i<=n; i++) 14 for(int j=m; j>=c[i]; j--)//1.这里逆序的原因是:用f[j]保存原来f[i-1][j]和f[i-1][j-c[i]]+v[i]的信息,要使前面的信息为i-1层的信息,必须后更新 15 //2.j>=c[i]的原因是:背包大小比c[i]小的显然不装,状态不变;另一个是f[j-c[i]]中的下标应不小于0 16 f[j]=max(f[j],f[j-c[i]]+v[i]); 17 18 cout<<f[m]; 19 return 0; 20 }
二、完全背包
题目:
有 N 种物品和一个容量为 V 的背包,每种物品都有无限件可用。放入第 i 种物品 的费用是 Ci,价值是 Wi。求解:将哪些物品装入背包,可使这些物品的价值总和最大。
输入格式 第一行两个整数,N,V,用空格隔开,分别表示物品种数和背包容积。 接下来有 N 行,每行两个整数 vi,wi,用空格隔开,分别表示第 i 种物品的体积和价值。 输出格式 输出一个整数,表示最大价值。 input: 4 5 1 2 2 4 3 4 4 5 output: 10
解法一:
套用01背包的理论,完全背包就是每个物品可选数目为[0,V/wi];故 f[i][j]=max{f[i-1][j-kc[i]]+kv[i] | 0<=k<=V/c[i]} ,每次状态确定需要多花k步。可以先优化去掉大于V的物品以及c更大且v更小的物品
解法二:
还记得01背包空间优化的逆序原因吗,为了保证新状态的确定用的是前一层的状态,所以逆序更新。但完全背包正相反,新状态的确定需要一个能选到本层的状态,所以应该且必须用顺序更新。
1 #include <bits/stdc++.h> 2 using namespace std; 3 #define maxn 1005 4 int f[maxn];//背包大小为i的最优解; 5 int c[maxn];//费用 6 int v[maxn];//价值 7 int main() 8 { 9 int n,m; 10 cin>>n>>m; 11 for(int i=1; i<=n; i++) 12 cin>>c[i]>>v[i]; 13 for(int i=1; i<=n; i++) 14 for(int j=c[i]; j<=m; j++)//与01背包的空间优化仅是两者更新方向不同 15 f[j]=max(f[j],f[j-c[i]]+v[i]); 16 17 cout<<f[m]; 18 return 0; 19 }
标签:...,背包,九讲,int,maxn,物品,价值,解法 来源: https://www.cnblogs.com/better150/p/12248646.html