01背包

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/hy971216/article/details/80341628

01背包问题

有n件物品,每件物品的重量为w[i],价值为c[i]。现有一个容量为V的背包,问如何选取物品放入背包,使得背包
内物品的总价值最大。其中每件物品都只有1件。
样例:

5 8 //n,v

3 5 1 2 2 //w[i]

4 5 2 1 3 //c[i]

暴力枚举的想法

枚举每一件物品放或者不放进背包,显然每件物品都有两种选择,因此n件物品就有2^n种情况,
显然不是理想的解决方案

动态规划解法

时间复杂度为O(nV)

令dp[i][v]表示前i件物品(1<=i<=n,0<=v<=V)恰好装入容量为v的背包中所能获得的最大价值。

考虑对第i件物品的选择策略,有两种策略:

  1. 不放第i件物品,那么问题转化为前i-1件物品恰好装入容量为v的背包中所能获得的最大价值,即dp[i-1][v]

  2. 放第i件物品,那么问题转化为前i-1件物品恰好装入容量为v-w[i]的背包中所能获得的最大价值,即dp[i-1][v-w[i]]+c[i]

由此得出状态转移方程:
dp[i][v] = max{dp[i-1][v],dp[i-1][v-w[i]]+c[i]} (1<=i<=n,w[i]<=v<=V)

边界: dp[0][v] = 0(0<=v<=V)(即前0件物品放入任何容量为v的背包中都只能获得价值0)

for(int i=1;i<=n;i++){
    for(int v=w[i];v<=V;v++){
        dp[i][v] = max(dp[i-1][v],dp[i-1][v-w[i]]+c[i]);
    }
}

这段代码时间复杂度与空间复杂度均为O(nV),其中时间复杂度无法优化,但空间复杂度可以
优化的关键在于开一个一维数组dp[v],枚举方向改变为i从1到n,v从V到0(逆序)

状态转移方程: dp[v] = max{dp[v],dp[v-w[i]]+c[i]} (1<=i<=n,w[i]<=v<=V)

for(int i=1;i<=n;i++){
    for(int v=V;v>=w[i];v--){
        dp[v] = max(dp[v],dp[v-w[i]]+c[i]);
    }
}

此时空间复杂度为O(V)
说明:如果是二维数组存放,v的枚举顺序或逆序皆可;但如果用一维数组存放,v的枚举必须为逆序

#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn = 100;
const int maxv = 1000;
int w[maxn],c[maxn],dp[maxv];
int main()
{
    int n,V;
    scanf("%d%d",&n,&V);
    for(int i=0;i<n;i++){
        scanf("%d",&w[i]);
    }
    for(int i=0;i<n;i++){
        scanf("%d",&c[i]);
    }
    for(int v=0;v<=V;v++){
        dp[v] = 0;
    }
    for(int i=1;i<=n;i++){
        for(int v=V;v>=w[i];v--){
            dp[v] = max(dp[v],dp[v-w[i]]+c[i]);
        }
    }
    int max = 0;
    for(int v=0;v<=V;v++){
        if(dp[v]>max){
            max = dp[v];
        }
    }
    printf("%d\n",max);
    return 0;
}
阅读更多
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页