• acwing 002 零一背包问题


    地址 https://www.acwing.com/problem/content/description/2/

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

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

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

    输入格式
    第一行两个整数,N,V,用空格隔开,分别表示物品数量和背包容积。

    接下来有 N 行,每行两个整数 vi,wi,用空格隔开,分别表示第 i 件物品的体积和价值。

    输出格式
    输出一个整数,表示最大价值。

    数据范围
    0<N,V≤1000
    0<vi,wi≤1000

    样例
    输入样例
    4 5
    1 2
    2 4
    3 4
    4 5
    输出样例:
    8

    算法1
    (初步动态规划)
    最开始的动态规划想法 就是二维数组
    dp[i][j]记录 在选择i个物品下 j背包容积下的最大价值
    状态转移方程式

    C++ 代码

     1 #include <iostream>
     2 #include <algorithm>
     3 
     4 using namespace std;
     5 
     6 const int N= 1010;
     7 
     8 int n,m;
     9 
    10 int dp[N][N];
    11 int v[N];
    12 int w[N];
    13 
    14 int main()
    15 {
    16 cin >> n >> m;
    17 
    18 for(int i = 1;i <= n;i++){
    19 cin >> v[i] >> w[i];
    20 }
    21 
    22 for(int i = 1;i<=n;i++){
    23 for(int j = 1;j<=m;j++){
    24 dp[i][j] = dp[i-1][j];
    25 if(j >= v[i])
    26 dp[i][j] = max(dp[i-1][j] , dp[i-1][j-v[i]]+w[i]);
    27 }
    28 }
    29 
    30 cout << dp[n][m];
    31 
    32 
    33 return 0; 
    34 }
    View Code

    根据acwing up主的视频和网络上的《背包九讲》 空间存储上还可在优化
    算法2
    (进阶动态规划)
    我们可以将二维DP降为一维DP
    这个可以看做在i的循环情况下 我们每次计算j(容量)的可装的最大价值
    那么初次进入i+1 的循环时候,我们需要利用i轮次的结果来计算i+1的结果
    dp[i+1][j]在0 1 情况下只有两种可能 在上一轮的结果下 选择放入当前物品 或者不放入当前物品
    1 不放入当前物品的话
    那么 dp[i+1][j] = dp[i][j]; //利用上一轮的结果
    2 放入当前物品的话
    那么 dp[i+1][j] = dp[i][j-v[i]]+w[i]; //利用上一轮的结果

    由于我们始终只需要最新的i+1层的结果 那么实际上可以使用一维数组dp[j]来记录每层的结果,
    当从i层进入i+1层后,dp[i+1][j]的结果 实际可以使用dp[i][j]存储,其实就是 dp[j] = dp[j];j++(或者j–);

    由于计算机语言的特性,在执行dp[j] = dp[j]的时候 我们必须保证等号右边的dp[j]是没被改动过的,这就要保证j是降序
    因为dp[j]= max(dp[j],dp[j-v[i]]); dp[j]的赋值对低于j的[j-v[i]]有依赖,必须降序排列,才能保证赋值的时候等号右边的dp[j]是没被改动过的

    C++ 代码

     1 #include <iostream>
     2 #include <algorithm>
     3 
     4 using namespace std;
     5 
     6 const int N= 1010;
     7 
     8 int n,m;
     9 
    10 int dp[N];
    11 int v[N];
    12 int w[N];
    13 
    14 int main()
    15 {
    16 cin >> n >> m;
    17 
    18 for(int i = 1;i <= n;i++){
    19 cin >> v[i] >> w[i];
    20 }
    21 
    22 for(int i = 1;i<=n;i++){
    23 for(int j = m;j>= v[i];j--){
    24 dp[j] = max(dp[j] , dp[j-v[i]]+w[i]);
    25 }
    26 }
    27 
    28 cout << dp[m];
    29 
    30 return 0; 
    31 }
    View Code

    作者:defddr
    链接:https://www.acwing.com/solution/acwing/content/2170/
    来源:AcWing
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

    作 者: itdef
    欢迎转帖 请保持文本完整并注明出处
    技术博客 http://www.cnblogs.com/itdef/
    B站算法视频题解
    https://space.bilibili.com/18508846
    qq 151435887
    gitee https://gitee.com/def/
    欢迎c c++ 算法爱好者 windows驱动爱好者 服务器程序员沟通交流
    如果觉得不错,欢迎点赞,你的鼓励就是我的动力
    阿里打赏 微信打赏
  • 相关阅读:
    【调试】关于F9
    【vue】vue变量定义的位置
    【js】MVVM模型
    RE最全面的正则表达式----数字篇
    Spider & CrawlSpider
    论小脚本的重要性
    论小脚本的简单性3
    论小脚本的简单性2
    论小脚本的简单性
    git的常用命令
  • 原文地址:https://www.cnblogs.com/itdef/p/10906302.html
Copyright © 2020-2023  润新知