背包问题——动态规划算法求解

文章介绍了如何使用动态规划解决01背包问题,其中每个物品具有体积和价值,目标是选择物品使得总价值最大且不超过背包容量。通过建立递归方程并使用一维数组优化存储空间,实现了问题的解决方案,并给出了优化后的C++代码实现。

1.问题描述

N 件物品和一个容量是 V的背包。每件物品只能使用一次。

i件物品的体积是 vi,价值是 wi

求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。

输出最大价值。

首先,动态规划的基本理念就是将大问题分解为性质相同的小问题,对每个小问题求的解记录下来,避免重复求解。其次,我们读题确定用动态规划求解后,可以列出递归方程,利用方程可以递推出最优解。

对于01背包问题,只有两种可能性:装/不装,

设f[i][j] i表示前i个物品,j表示当前容量 v[i]表示第i个物品的体积

对于装/不装 如果都满足限制条件,即可以同时出现,我们需要比较这两种情况的累计价值谁更大。

例:背包总容积V为5,以下是四件物品的体积和各自价值


体积vi

价值wi

物品1

1

2

物品2

2

4

物品3

3

4

物品4

4

5

(行表示背包从0~V的体积变化,列表示第几个物品的序号,数组值表示前i件物品可以产生的最大价值)

0

1

2

3

4

5

0

0

0

0

0

0

0

1

0

2

2

2

2

2

2

0

2

4

6

6

6

3

0

2

4

6

6

8

4

0

2

4

6

6

8

  • 如果装入第i个物品,则前i个物品的体积不能超过背包体积,体积改变,价值改变

即f[i][j]=f[i-1][j-v[i]]+w[i];

  • 如果不装,则重量不变,价值不变

即f[i][j]=f[i-1][j];

代码如下所示

#include<iostream>
#include<string>
#include<algorithm>

using namespace std;

int f[1011][2011];
int N,V;
int v[1011],w[2011];
int main(){
    cin>>N >>V;
    for(int i=1;i<=N;i++){
        cin>>v[i] >>w[i];
    }
    for(int i=1;i<=N;i++){
        for(int j=1;j<=V;j++){
            f[i][j]=f[i-1][j];
            if(v[i]<=j)//第i个装入
                f[i][j]=max(f[i][j],f[i-1][j-v[i]]+w[i]);
                
        }
    }
    cout<<f[N][V]<<endl;
    return 0;
}

2.代码优化

其实可以用一维数组来表示最优值,即将数组压缩

代码改动并不大,我们来看两个for循环中的语句:

for(int i=1;i<=N;i++){

for(int j=1;j<=V;j++){

f[i][j]=f[i-1][j];

if(v[i]<=j)//第i个装入

f[i][j]=max(f[i][j],f[i-1][j-v[i]]+w[i]);

}

}

先看第一个对i进行循环的for语句,它的作用是将数据处理能遍历到每一行,有N个物品就有N行,所以我们只要保证第一个for循环存在,就知道这是到了第几行,因此f[i][j]可以直接写为f[j];

再来看对第二个for循环的处理,它是对每一列的遍历,强制去掉二维后f[j]=max(f[j],f[j-v[i]]+w[i]);

此时出现了问题,f[j-v[i]]是在第i行、第j-v[i]列的状态,但是我们需要的是第i-1行、第j-v[i]列的状态。

j按找从1~V变化显然不正确,会重复算第i行前面已经求出的解,因此我们使j逆序变化,

即for(j=V;j>=v[i];j--){

f[j]=max(f[j],f[j-v[i]]+w[i]);

}

完整利用一维数组的代码为

#include<iostream>
#include<string>
#include<algorithm>

using namespace std;

int f[1011];
int N,V;
int v[1011],w[1011];
int main(){
    cin>>N >>V;
    for(int i=1;i<=N;i++){
        cin>>v[i] >>w[i];
    }
    for(int i=1;i<=N;i++){
        for(int j=V;j>=v[i];j--)
                f[j]=max(f[j],f[j-v[i]]+w[i]);
            
    }
    cout<<f[V]<<endl;
    return 0;
}

至此,01背包——动态规划求解结束。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值