动态规划DP 背包问题 完全背包问题(题目分析+C++完整代码)
概览检索
动态规划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;
}