动态规划初步-01背包问题&&一维数组(空间复杂度优化)

时间:2022-06-19 17:08:12

题目链接:51nod1085 背包问题


问题描述:

有n个重量和价值分别为wi,vi的物品,从这些物品中挑选出总重量不超过m的物品,求所有挑选方案中价值总和的最大值。


思路分析:

问题可以看做往一个载重量为m的背包中装入有限数量的物品,求装入物品的最大价值。这里物品的件数都为1,所以每个物品都只有两种选择,要么放入背包,要么不放。在背包容量为j时,对前i件物品来说,设它的最大价值为dp[i][j],它的最大价值状态转移公式为:

//当第i件物品比背包容量还大时,dp[i][j]等于前i-1件物品放入这个背包的最大价值。

dp[i][j]=dp[i-1] [j]                                               (j<w[i])   

//当第i件物品能放入背包时,分为两种情况,选择放和不放,不放的话和上面公式相同,放的话则背包容量减去第i件物品的重量再去装前i-1件物品,所得的最大价值加上第i件物品的价值。两种情况中较大的那种即为最优解。

dp[i][j]=max(dp[i-1] [j],dp[i-1] [j-w [i] ]+v[i])        (j>=w[i])

参考代码:

#include"cstdio"
#include"algorithm"
using namespace std;
int N,W;
int w[105],p[105];
int dp[10007][105]= {0};
void DP()
{
        for(int i=1; i<=W; i++)
            for(int j=1; j<=N; j++)
        dp[i][j]=w[j]<=i?max(dp[i-w[j]][j-1]+p[j],dp[i][j-1]):dp[i][j-1];
}
int main()
{
    scanf("%d%d",&N,&W);
    for(int i=1; i<=N; i++)
        scanf("%d%d",&w[i],&p[i]);
    DP();
    printf("%d\n",dp[W][N]);
    return 0;
}


看了dd大牛的背包九讲后,对于01背包问题又有了更深层次的理解,从上面的分析可以看出,在每次更新dp数组时,总是在当前物品数-1的基础上的,能不能直接用一维数组来保存物品数-1时的值呢?只需把空间花费从大到小来构成for循环即可。

参考代码:

#include"cstdio"
#include"cstring"
#include"algorithm"
using namespace std;
int N,W;
int w[105],p[105];
int dp[10005];
void DP()
{
    for(int i=1;i<=N;i++)
        for(int j=W;j>0;j--)
    {
        dp[j]=w[i]<=j?max(dp[j-w[i]]+p[i],dp[j]):dp[j];
    }
}
int main()
{
    memset(dp,0,sizeof(dp));
    scanf("%d%d",&N,&W);
    for(int i=1;i<=N;i++)
    {
        scanf("%d%d",&w[i],&p[i]);
    }
    DP();
    printf("%d\n",dp[W]);
    return 0;
}