一维数组解01背包问题(总结各种大神的分析)

经历过拼多多的笔试题,就知道该多学学动态规划算法了。。

问题描述:

有n和重量和价值分别为Wi,Vi的物品,从这些物品中挑选出总质量不超过C的物品,如何挑选使得总价值量最大?

思路分析:

序号weightvalue12345678910
a25055881313141616
b3301388911111414
c56011889991414
d480118899999
e210111111111

这个表格是自底向上从左到右的顺序,e2单元格表示最多容重2时,只有e物品可选时,最大价值为1

c3表示最多容重为3时,只有c.d.e物品可选时,最大价值为1,因为d和e都大于3,装不了。

a8的值是14,怎么得到?

根据01背包的状态转换方程: f[i,j] = Max{ f[i-1,j-Wi]+Pi( j >= Wi ),  f[i-1,j] }

f[i-1][j]表示b[8]的值为11,f[i-1],j-wi]表示b6的值为9,9+5=14>11,因此a8的值为14。

分析原文地址:https://blog.csdn.net/mu399/article/details/7722810

当背包容量为j时,已经放入了i件物品,最大价值为d[i]d[j]

当第i件物品比背包容量还大时,不能放,所以,d[i][j]=d[[i-1][j];

当第i件物品比背包容量小时,就要判断两种情况:不放的话,和上式相同,放的话,背包容量-第i件物品的质量再去装前i-1件物品,所得得最大价值加上第i件物品的价值,两者较大值即为最优解。d[i][j]=max(dp[i-1][j],dp[i-1][j-w[i]]+v[i])

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <iostream>
#include <algorithm>
using namespace std;
#define EMPTY
#define INF -65536
const int C=10;//容量capability
int n;//物品个数
int w[15],v[15];//物品个数,物品质量weight,物品价值value
int dp[1000][C+1]={0};
int main(){
    scanf("%d ",&n);
    for(int i=1;i<=n;i++)scanf("%d",&w[i]);
    for(int i=1;i<=n;i++)scanf("%d",&v[i]);
    #ifdef EMPTY//要求价值最大化,可以不满
        for(int i=0;i<=n;i++)dp[i][0]=0;
        for(int i=0;i<=C;i++)dp[0][i]=0;
    #else//必须装满
        dp[0][0]=0;
        for(int i=1;i<=C;i++)dp[0][i]=INF;
        for(int i=1;i<=n;i++)dp[i][0]=INF;
    #endif
     for(int i=1;i<=C;i++){
         for(int j=1;j<=n;j++){
             dp[i][j]=w[j]<=i?max(dp[i][j-1],dp[i-w[j]][j-1]+v[j]):dp[i][j-1];
         }
     }
     cout<<dp[C][n]<<endl;
    return 0;
}


从空间花费从大到小来构成for循环的话,就可以直接用一维数组来保存物品数-1 的值。

当背包容量为j时,已经放入了i件物品,最大价值为d[j]

当第i件物品比背包容量还大时,d[j]=d[j];

当第i件物品比背包容量小时,就要判断两种情况:不放的话,和上式相同,放的话,背包容量-第i件物品的质量再去装前i-1件物品,所得得最大价值加上第i件物品的价值,两者较大值即为最优解。d[j]=max(dp[j],dp[j-w[i]]+v[i])

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <iostream>
#include <algorithm>
using namespace std;
#define EMPTY
#define INF -65536
const int C=10;//容量capability
int n;//物品个数
int w[15],v[15];//物品个数,物品质量weight,物品价值value
int dp[C+1];
int main(){
    scanf("%d ",&n);
    for(int i=1;i<=n;i++)scanf("%d",&w[i]);
    for(int i=1;i<=n;i++)scanf("%d",&v[i]);
    #ifdef EMPTY//要求价值最大化,可以不满
        for(int i=0;i<=C;i++)dp[i]=0;
    #else//必须装满
        dp[0]=0;
        for(int i=1;i<=C;i++)dp[i]=INF;
    #endif
     for(int i=1;i<=n;i++){
         for(int j=C;j>0;j--){
             dp[j]=w[i]<=j?max(dp[j],dp[j-w[i]]+v[i]):dp[j];//注意这个+v[i]是在dp[]外面加的
         }
     }
     cout<<dp[C]<<endl;
    return 0;
}


代码博文地址:https://blog.csdn.net/stack_queue/article/details/52734100

 

  • 4
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值