题解 | #完全背包问题#
题目描述
设有n种物品,每种物品有一个重量及一个价值。但每种物品的数量是无限的,同时有一个背包,最大载重量为M,今从n种物品中选取若干件(同一种物品可以多次选取),使其重量的和小于等于M,而价值的和为最大。
输入描述
第一行:两个整数,M(背包容量,M<=200)和N(物品数量,N<=30);
第2..N+1行:每行二个整数Wi,Ci,表示每个物品的重量和价值。
输出描述
输出最大总价值。格式:“max=12”
完全背包问题
每种物品有无穷多个,物品i的体积:w[i]、价值:v[i]
dp[i][j]:前i种物品装进容量为j的背包所获得的最大价值
与0-1背包唯一区别:dp[i][j]=max(dp[i-1][j],dp[i][j-w[i]]+v[i]) 放得下时还可以继续选
#include<iostream>
using namespace std;
const int maxn=1001;
int w[maxn];
int v[maxn];
int dp[maxn][maxn];
int best(int sum,int n){
for(int i=0;i<=n;i++){
dp[i][0]=0;
}
for(int i=0;i<=sum;i++){
dp[0][i]=0;
}
for(int i=1;i<=n;i++){
for(int j=1;j<=sum;j++){
if(w[i]>j)dp[i][j]=dp[i-1][j];
else dp[i][j]=max(dp[i-1][j],dp[i][j-w[i]]+v[i]);//唯一修改
}
}
return dp[n][sum];
}
int main(){
int sum,n;
while(scanf("%d%d",&sum,&n)!=EOF){
for(int i=1;i<=n;i++)scanf("%d%d",&w[i],&v[i]);
printf("max=%d\n",best(sum,n));
}
}
优化:压缩空间
- dp[i][j]只取决于上一行dp[i-1][j]和本行前面dp[i][j-w[i]]的值
- 故从前往后更新
#include<iostream>
using namespace std;
const int maxn=1001;
int w[maxn];
int v[maxn];
int dp[maxn];
int best(int sum,int n){
for(int i=0;i<=sum;i++){
dp[i]=0;
}
for(int i=1;i<=n;i++){
for(int j=w[i];j<=sum;j++){//从前往后更新
dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
}
}
return dp[sum];
}
int main(){
int sum,n;
while(scanf("%d%d",&sum,&n)!=EOF){
for(int i=1;i<=n;i++)scanf("%d%d",&w[i],&v[i]);
printf("max=%d\n",best(sum,n));
}
}
algorithm 文章被收录于专栏
外源题解补充
