背包9讲之2 完全背包专题

来源:互联网 发布:linux shell脚本 echo 编辑:程序博客网 时间:2024/06/13 02:56

完全背包问题

给出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;}



观察   dp[i][j] = max(dp[i-1][j],dp[i][j-v[i]]+p[i])

不难发现也可以用滚动数组将其改成一维的.

不同的是我们内循环要正序而不是逆序

下面是一维数组的完全背包代码

#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;}



0 0
原创粉丝点击