【动态规划专栏】背包问题:01背包

简介: 【动态规划专栏】背包问题:01背包


题目来源

本题来源为:

牛客网01背包

题目描述

题目解析

我们分析一下本道题目,体积为5,有三个物品。

有两个问题:

1.求这个背包至多能装多大价值的物品?

2.若背包恰好装满,求至多能装多大价值的物品?

这两个问题区别就是,第一个问题背包可以装满可以不装满

而第二个问题是恰好装满。

算法原理

我们先说一下什么是背包问题:

你现在有一个背包,地上有一堆物品,每个物品有自己对应的体积与价值,而每个背包的容量有限,你需要在保证自己的书包容量的同时保障价值最大。这就是背包问题。

背包问题分为好多种:

而01背包和完全背包为最为常见的两种。

01背包就是里面的物品只能选一次或者不选。
完全背包是里面的物品可以没有次数限制。

问题1.1.状态表示

经验+题目要求

这里不能用一维而是要用二维dp表,因为不仅要保证价值还要保证物品的容量,因此用二维的dp表

对于本题而言就是:

dp[i][j]表示:从前i个物品中挑选,总体积不超过j,所有选法中,能挑选出来的最大价值

2.状态转移方程

还是根据最后一步的情况来进行情况讨论

因此状态方程为:

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

3.初始化

跟之前一样,在原数组加一行一列

4.填表顺序

从上往下

5.返回值

dp[n][v]

问题2.1.状态表示

问题二跟问题一基本一样:

经验+题目要求

对于本题而言就是:

dp[i][j]表示:从前i个物品中挑选,总体积正好等于j,所有选法中,能挑选出来的最大价值

2.状态转移方程

还是根据最后一步的情况来进行情况讨论

因此状态方程为:

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

3.初始化

跟之前一样,在原数组加一行一列

4.填表顺序

从上往下

5.返回值

dp[n][v]

代码实现

动态规划的代码基本就是固定的四步:

1.创建dp表
2.初始化
3.填表
4.返回值

本题完整代码实现:

#include <iostream>
#include <string.h>
using namespace std;
const int N=1010;
int n,V,v[N],w[N];
int dp[N][N];
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++)
        {
            dp[i][j]=dp[i-1][j];
            if(j>=v[i])
                dp[i][j]=max(dp[i][j],dp[i-1][j-v[i]]+w[i]);
        }
    }
    cout<<dp[n][V]<<endl;
    //解决第二问:
    memset(dp,0,sizeof dp);
    for(int j=1;j<=V;j++)
    dp[0][j]=-1;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=V;j++)
        {
            dp[i][j]=dp[i-1][j];
            if(j>=v[i]&&dp[i-1][j-v[i]]!=-1)
                dp[i][j]=max(dp[i][j],dp[i-1][j-v[i]]+w[i]);
        }
    }
     cout<<(dp[n][V]==-1?0:dp[n][V])<<endl;
}

空间优化:

空间优化有两种优化方式:

1.利用滚动数组进行优化

2.直接在原来的代码上进行修改

代码实现:

#include <iostream>
#include <string.h>
using namespace std;
const int N=1010;
int n,V,v[N],w[N];
int dp[N];
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--)
                dp[j]=max(dp[j],dp[j-v[i]]+w[i]);
    }
    cout<<dp[V]<<endl;
    //解决第二问:
    memset(dp,0,sizeof (dp));
    for(int j=1;j<=V;j++)
    dp[j]=-1;
    for(int i=1;i<=n;i++)
    {
        for(int j=V;j>=v[i];j--)
        {
            if(dp[j-v[i]]!=-1)
                dp[j]=max(dp[j],dp[j-v[i]]+w[i]);
        }
    }
     cout<<(dp[V]==-1?0:dp[V])<<endl;
}
相关文章
|
4月前
|
算法
【动态规划专栏】背包问题:1049. 最后一块石头的重量 II
【动态规划专栏】背包问题:1049. 最后一块石头的重量 II
46 0
|
3月前
|
算法 程序员
程序员必知:动态规划——背包问题1:01背包
程序员必知:动态规划——背包问题1:01背包
23 0
|
3月前
|
存储 算法
动态规划(背包问题)
动态规划(背包问题)
|
4月前
|
消息中间件 Kubernetes NoSQL
动态规划- 背包问题总结(二)
动态规划- 背包问题总结(二)
|
4月前
|
消息中间件 Kubernetes NoSQL
动态规划- 背包问题总结(一)
动态规划- 背包问题总结(一)
BXA
|
算法 程序员 决策智能
动态规划详解背包问题及实践(附C++代码)
背包问题是一个经典的组合优化问题,它可以被抽象为一个把物品放入背包中的过程,以求最终背包中物品价值的最大化
BXA
545 0
|
9月前
动态规划入门01背包
基本思路: 1.n物品个数,m为背包体积,使用w[i]记录权值,v[i]记录体积,f[i][j]记录选择前i个物体,在不超过j体积下的最优解 最终答案就是f[n][m]; 2.f[i][j]的状态依赖于之前的状态;即f[i[][j]依赖于f[i - 1][j]的状态;也可以理解为所有的状态由f[0][j]推得 f[i][j]的状态不好算出来,但是f[0][j]的状态必定为0,由f[0][j]可以算出f[1][j]的,由f[1][j]又可算出f[2][j]的递推可得出全部。f[1][1] f[2][2] f[3][3]他们每个都减去第i个物品的权值最大值仍不变,最后在加上w[i]即可 即( f[
50 0
|
存储 算法
动态规划之背包问题
动态规划之背包问题
86 0
|
算法 C语言 C++
【动态规划】背包问题(01背包,完全背包)
有 N 件物品和一个容量是 V 的背包。每件物品只能使用一次。
112 0
动态规划:多重背包问题
动态规划:多重背包问题
63 0