【蓝桥杯】小明的背包2(DP)

本文介绍了如何使用动态规划方法解决背包问题,通过构建二维数组dp[i][j]来计算在给定物品和背包容量下,选取商品的最大价值。文章详细解释了递推公式和代码实现,展示了C++中的解决方案。
摘要由CSDN通过智能技术生成

一.题目描述

二.问题分析 

这是一个典型的动态规划问题。

我们使用一个二维数组来解决问题,dp[i][j]表示从第1个到第i个物品中进行选取,装入容积为j的背包中商品的总价值。

其实这里隐含了一个初始条件,即dp[i][0]=0,即背包容量为0时,无论如何选取商品,其价值总为0。

如图所示,由于商品的编号从1开始,上图中箭头所指的元素值均为0。

 

有了初始条件,就需要dp的递推公式。

我们考虑最简单的一种情况,即商品的种类为1时。dp[1][j]的值完全取决于容量为j的背包能够装入多少件该商品。

此时,我们便能够将上图中绿色箭头所指的一行填上数字。

此时,我们再考虑复杂一点的情况,商品种类变为i。

也就是说,我们需要将上图表格中第i行填入。 

此时考虑产生的最大价值,我们就需要去考虑i种商品。我们可以使用已经存在的数据,来对i种商品的最大价值进行构建。

背包的容积j从0开始依次递增到v,我们考虑dp[i][j]。

我们可以使用dp[i-1][j]的值对dp[i][j]进行初始化。注意:此时这个二维数组前i-1行的数据均填写完毕,均有初值。

dp[i][j]=dp[i-1][j],表示的含义就是不加入第i种产品,与此同时,我们还需要考虑加入第i种产品,问题来了,那需要加几个呢,所以嵌入了一个内循环,k从1开始,一直循环到背包容量所能承受的最大件数。每次都要去看,max(dp[i][j],dp[i-1][j-k*item[i].weight]+k*item[i].value),哪个值更大。注意,这里一定要用dp[i][j]。

最终,构建出了这个二维数组的所有值,dp[n][v]就是我们要的结果。

具体代码如下:

//小明的背包
#include <iostream>

using namespace std;

const int N=1e3+10;
int n,v;//n物品种类,v背包容积

struct Item{
    int weight;
    int value;
}item[N];

int dp[N][N]={0};//dp[i][j]表示从第1个到第i个物品中进行选取装入容积为j的背包中

int main(){
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    cin>>n>>v;
    for(int i=0;i<n;i++){
        cin>>item[i+1].weight>>item[i+1].value;
    }
    for(int i=1;i<=n;i++){//外层循环商品的种类
        for(int j=0;j<=v;j++){//内层循环背包的容积
            dp[i][j]=dp[i-1][j];//表示不放入第i个产品
            for(int k=1;k*item[i].weight<=j;k++){
                dp[i][j]=max(dp[i][j],dp[i-1][j-k*item[i].weight]+k*item[i].value);
            }
        }
    }
    cout<<dp[n][v]<<'\n';
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值