概览检索
动态规划DP 概览(点击链接跳转)
动态规划DP 背包问题 概览(点击链接跳转)
完全背包问题
原题链接
AcWiing 3. 完全背包问题
题目描述
有 N种物品和一个容量是 V的背包,每种物品都有无限件可用。
第 i种物品的体积是 vi,价值是 wi。
求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。
输出最大价值。
输入格式
第一行两个整数,N,V,用空格隔开,分别表示物品种数和背包容积。
接下来有 N行,每行两个整数 vi,wi,用空格隔开,分别表示第 i种物品的体积和价值。
输出格式
输出一个整数,表示最大价值。
数据范围
0<N,V≤1000
0<vi,wi≤1000
输入样例
4 5
1 2
2 4
3 4
4 5
输出样例:
10
题目分析
完全背包:对于每个物品可以选0,1,2···个(无限件可用)。
闫氏DP分析法
f [ i , j ] f[i,j] f[i,j] 表示从1~i 个物品中选择且总体积不超过 j 的选法中价值最大的那个。
对于第i个物品,
可以选0个 i,即在 0~i -1 个物品中选择,体积不超过j,即 f [ i − 1 , j ] f[i-1,j] f[i−1,j]。
可以选1个 i,同时在 0~i -1 个物品中选择,体积不超过 j − v [ i ] j-v[i] j−v[i],即 f [ i − 1 , j − v [ i ] ] + w [ i ] f[i-1,j-v[i]]+w[i] f[i−1,j−v[i]]+w[i]。
···
可以选k个 i,同时在 0~i -1 个物品中选择,体积不超过 j − k × v [ i ] j-k \times v[i] j−k×v[i],即 f [ i − 1 , j − k × v [ i ] ] + k × w [ i ] f[i-1,j-k \times v[i]]+k \times w[i] f[i−1,j−k×v[i]]+k×w[i]。
其中,k的值由背包总容量决定,要保证 j ≥ k × v [ i ] j\geq k \times v[i] j≥k×v[i],
即 k = ⌊ j / v [ i ] ⌋ k=\lfloor j/v[i] \rfloor k=⌊j/v[i]⌋。
综上,
f [ i , j ] f[i,j] f[i,j] 即为上述所有结果的最大值。
f [ i , j ] = m a x ( f [ i − 1 , j ] , f [ i − 1 , j − k × v [ i ] ] + k × w [ i ] ) f[i,j]=max(f[i-1,j],f[i-1,j-k \times v[i]]+k \times w[i]) f[i,j]=max(f[i−1,j],f[i−1,j−k×v[i]]+k×w[i])
优化版
观察状态计算公式:
f [ i , j ] = m a x ( f [ i − 1 , j ] , f [ i − 1 , j − v ] + w , f [ i − 1 , j − 2 v ] + 2 w , ⋅ ⋅ ⋅ , f [ i − 1 , j − k v ] + k w ) f[i,j]=max(f[i-1,j],f[i-1,j-v]+w,f[i-1,j-2v]+2w,···,f[i-1,j-kv]+kw) f[i,j]=max(f[i−1,j],f[i−1,j−v]+w,f[i−1,j−2v]+2w,⋅⋅⋅,f[i−1,j−kv]+kw)
f [ i , j − v ] = m a x ( f [ i − 1 , j − v ] , f [ i − 1 , j − 2 v ] + w , f [ i − 1 , j − 3 v ] + 2 w , ⋅ ⋅ ⋅ , f [ i − 1 , j − k v ] + ( k − 1 ) w ) f[i,j-v]=max(f[i-1,j-v],f[i-1,j-2v]+w,f[i-1,j-3v]+2w,···,f[i-1,j-kv]+(k-1)w) f[i,j−v]=max(f[i−1,j−v],f[i−1,j−2v]+w,f[i−1,j−3v]+2w,⋅⋅⋅,f[i−1,j−kv]+(k−1)w)
对比可得:
可得,
f [ i , j ] = m a x ( f [ i − 1 , j ] , f [ i , j − v ] + w ] f[i,j]=max(f[i-1,j],f[i,j-v]+w] f[i,j]=max(f[i−1,j],f[i,j−v]+w]
完整代码
朴素版
#include <iostream>
#include <algorithm>
using namespace std;
const int N=1010;
int n,m;
int v[N],w[N];
int f[N][N];
int main(){cin>>n>>m;for(int i=1;i<=n;i++) cin>>v[i]>>w[i];//遍历每个物品for(int i=1;i<=n;i++)for(int j=0;j<=m;j++)//选k个第i个物品for(int k=0;k<=j/v[i];k++)f[i][j]=max(f[i][j],f[i-1][j-k*v[i]]+k*w[i]);cout<<f[n][m]<<endl;return 0;
}
优化版
#include <iostream>
#include <algorithm>
using namespace std;
const int N=1010;
int n,m;
int w[N],v[N];
int f[N][N];
int main(){cin>>n>>m;for(int i=1;i<=n;i++) cin>>v[i]>>w[i];for(int i=1;i<=n;i++)for(int j=0;j<=m;j++){f[i][j]=f[i-1][j];if(j>=v[i]) f[i][j]=max(f[i][j],f[i][j-v[i]]+w[i]);}cout<<f[n][m]<<endl;return 0;
}
空间优化一维
#include <iostream>
#include <algorithm>
using namespace std;
const int N=1010;
int n,m;
int v[N],w[N];
int f[N]; //一维
int main(){cin>>n>>m;for(int i=1;i<=n;i++) cin>>v[i]>>w[i];for(int i=1;i<=n;i++){for(int j=v[i];j<=m;j++){f[j]=max(f[j],f[j-v[i]]+w[i]);}}cout<<f[m]<<endl;return 0;
}