完全背包问题
给出n种物品的体积v[n]和价值p[n] 其中每一种物品都有无限多个.给你一个体积为V的背包 问其能装下的最大价值是多少呢?
解题思路:
有了01背包的基础 不难得出完全背包的一个状态转移方程:
dp[i][j] = max(dp[i-1][j-k*v[i]]+k*p[i] , k = 0,1,2,3....)
这就是完全背包的第一个状态转移方程,不难理解.
下面我们模仿01背包的状态转移方程再来写一个,也就是第二个完全背包的状态转移方程
dp[i][j] = max(dp[i-1][j],dp[i][j-v[i]]+p[i])
怎么来理解呢? 前面的一个dp[i-1][j]即为本次不选第i个物品,后面的dp[i][j-v[i]]+p[i]即为"本次选一个第i个物品" 与01背包的区别就是第二个dp[i]而不是dp[i-1].
下面放一个用二维数组写的完全背包
#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
const int maxn = 100010;//这应该是背包容积的最大值
int v[20];
int p[20];
int dp[20][maxn];
int main()
{
int n,V;
scanf("%d%d",&n,&V);
for(int i = 1 ; i <= n ; i ++) scanf("%d",&p[i]);
for(int i = 1 ; i <= n ; i ++) scanf("%d",&v[i]);
for(int i = 0 ; i <= n ; i ++){
dp[i][0] = 0;
dp[0][i] = 0;
}
for(int i = 1 ; i <= n ; i ++){
for(int j = 1 ; j <= V ; j ++){
if(v[i] <= j) dp[i][j] = max(dp[i-1][j],dp[i][j-v[i]]+p[i]);
else dp[i][j] = dp[i-1][j];
}
}
printf("%d\n",dp[n][V]);
return 0;
}
不难发现也可以用滚动数组将其改成一维的.
不同的是我们内循环要正序而不是逆序
下面是一维数组的完全背包代码
#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
const int maxn = 100010;//这应该是背包容积的最大值
int v[20];
int p[20];
int dp[maxn];
int main()
{
int n,V;
scanf("%d%d",&n,&V);
for(int i = 1 ; i <= n ; i ++) scanf("%d",&p[i]);
for(int i = 1 ; i <= n ; i ++) scanf("%d",&v[i]);
for(int i = 0 ; i <= n ; i ++) dp[i] = 0;
for(int i = 1 ; i <= n ; i ++){
for(int j = 1 ; j <= V ; j ++){
if(v[i] <= j) dp[j] = max(dp[j],dp[j-v[i]]+p[i]);
}
}
printf("%d\n",dp[V]);
return 0;
}
1972

被折叠的 条评论
为什么被折叠?



