zoukankan      html  css  js  c++  java
  • 背包问题系列(01背包、完全背包、多重背包)

    背包问题是一个经典的动态规划问题,问题可以描述为:给定一组物品,每种物品都有自己的重量和价格,在限定的总重量内,我们如何选择,才能使得物品的总价格最高。根据给定物品的数量,背包问题又可分为:

    1)每种物品只有一件,即01背包问题

    2)每种物品不限数量,可选取任意数量,即完全背包问题

    3)每种物品的数量已给定,不可超出该数量,即多重背包问题

    背包问题的重点:

    1)编写状态转移方程

    2)空间优化

     本文参考https://zhuanlan.zhihu.com/p/93857890,使用C++代码完成了三种问题的代码及空间优化代码

      1 #include <iostream>
      2 #include <vector>
      3 using namespace std;
      4 
      5 int max(int a, int b)
      6 {
      7     return a > b ? a : b;
      8 }
      9 
     10 int min(int a, int b)
     11 {
     12     return a < b ? a : b;
     13 }
     14 
     15 // 01背包问题,n件物品,重量为v
     16 int BagProblem_01(const vector<int> &weight, const vector<int> &value, int n, int v)
     17 {
     18     // 前i件物品背包限重为j的情况下的最大值
     19     vector<vector<int>> dp(n, vector<int>(v + 1, 0));
     20 
     21     for (int i = 0; i <= v; i++)
     22     {
     23         if (i >= weight[0])
     24         {
     25             dp[0][i] = value[0];
     26         }
     27     }
     28 
     29     for (int i = 1; i < n; i++)
     30     {
     31         for (int j = 1; j <= v; j++)
     32         {
     33             if (j < weight[i])
     34             {
     35                 dp[i][j] = dp[i - 1][j];
     36             }
     37             else
     38             {
     39                 dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]);
     40             }
     41         }
     42     }
     43 
     44     return dp[n - 1][v];
     45 }
     46 
     47 // 01背包问题--优化空间
     48 int BagProblem_01_optimize(const vector<int> &weight, const vector<int> &value, int n, int v)
     49 {
     50     // 前i件物品背包限重为j的情况下的最大值
     51     vector<int> dp(v + 1, 0);
     52 
     53     for (int i = 0; i <= v; i++)
     54     {
     55         if (weight[0] > v)
     56         {
     57             dp[0] = value[0];
     58         }
     59     }
     60 
     61     for (int i = 1; i < n; i++)
     62     {
     63         for (int j = v; j >= weight[i]; j--)    // dp[j]是由上一行<=j列推出,j需逆向枚举
     64         {
     65             dp[j] = max(dp[j], dp [j - weight[i]] + value[i]);
     66         }
     67     }
     68 
     69     return dp[v];
     70 }
     71 
     72 // 完全背包问题
     73 int BagProblem_complete(const vector<int> &weight, const vector<int> &value, int n, int v)
     74 {
     75     vector<vector<int>> dp(n, vector<int>(v + 1, 0));
     76 
     77     for (int j = 0; j <= v; j++)
     78     {
     79         dp[0][j] = j / weight[0] * value[0];
     80     }
     81 
     82     for (int i = 1; i < n; i++)
     83     {
     84         for (int j = 0; j <= v; j++)
     85         {
     86             if (j < weight[i])
     87             {
     88                 dp[i][j] = dp[i - 1][j];
     89             }
     90             else
     91             {
     92                 dp[i][j] = max(dp[i - 1][j], dp[i][j - weight[i]] + value[i]);
     93             }
     94         }
     95     }
     96 
     97     return dp[n - 1][v];
     98 }
     99 
    100 // 完全背包问题——优化空间
    101 int BagProblem_complete_optimize(const vector<int> &weight, const vector<int> &value, int n, int v)
    102 {
    103     vector<int> dp(v + 1, 0);
    104 
    105     for (int j = 0; j <= v; j++)
    106     {
    107         dp[j] = j / weight[0] * value[0];
    108     }
    109 
    110     for (int i = 1; i < n; i++)
    111     {
    112         for (int j = 0; j <= v; j++)    // dp[j]是由上一行j列和本行小于j列推出,因此需要正向枚举
    113         {
    114             if (j >= weight[i])
    115             {
    116                 dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);
    117             }
    118         }
    119     }
    120 
    121     return dp[v];
    122 }
    123 
    124 // 多重背包问题
    125 int BagProblem_multi(const vector<int> &weight, const vector<int> &value, const vector<int> &nums, int n, int v)
    126 {
    127     vector<vector<int>> dp(n, vector<int>(v + 1, 0));
    128 
    129     for (int j = 0; j <= v; j++)
    130     {
    131         int num = min(j / weight[0], nums[0]);
    132         dp[0][j] = num * value[0];
    133     }
    134 
    135     for (int i = 1; i < n; i++)
    136     {
    137         for (int j = 0; j <= v; j++)
    138         {
    139             if (j < weight[i])
    140             {
    141                 dp[i][j] = dp[i - 1][j];
    142             }
    143             else
    144             {
    145                 int num = min(j / weight[i], nums[i]);
    146                 for (int k = 0; k <= num; k++)
    147                 {
    148                     dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - k * weight[i]] + k * value[i]);
    149                 }
    150             }
    151         }
    152     }
    153 
    154     return dp[n - 1][v];
    155 }
    156 
    157 // 多重背包问题——优化空间
    158 int BagProblem_multi_optimize(const vector<int> &weight, const vector<int> &value, const vector<int> &nums, int n, int v)
    159 {
    160     vector<int> dp(v + 1, 0);
    161 
    162     for (int j = 0; j <= v; j++)
    163     {
    164         int num = min(j / weight[0], nums[0]);
    165         dp[j] = num * value[0];
    166     }
    167 
    168     for (int i = 1; i < n; i++)
    169     {
    170         for (int j = v; j >= 0; j--)    // dp[j]是由上一行<=j列推出,需要逆向枚举
    171         {
    172             int num = min(j / weight[i], nums[i]);
    173             for (int k = 0; k <= num; k++)
    174             {
    175                 if (j < k * weight[i])
    176                     continue;
    177                 dp[j] = max(dp[j], dp[j - k * weight[i]] + k * value[i]);
    178             }
    179         }
    180     }
    181 
    182     return dp[v];
    183 }
    184 
    185 int main()
    186 {
    187     int v = 10;
    188     int n = 5;
    189     vector<int> weight{ 2, 2, 4, 6, 3 };
    190     vector<int> value { 1, 3, 3, 5, 6 };
    191     vector<int> nums  { 1, 2, 3, 4, 1 };
    192 
    193     cout << BagProblem_01(weight, value, n, v) << endl;
    194     cout << BagProblem_01_optimize(weight, value, n, v) << endl;
    195 
    196     cout << BagProblem_complete(weight, value, n, v) << endl;
    197     cout << BagProblem_complete_optimize(weight, value, n, v) << endl;
    198 
    199     cout << BagProblem_multi(weight, value, nums, n, v) << endl;
    200     cout << BagProblem_multi_optimize (weight, value, nums, n, v) << endl;
    201 
    202     return 0;
    203 }
  • 相关阅读:
    QT 捕获事件(全局拦截)
    QT语言翻译
    QT,QLabel添加超链接
    解决VS+Qt不生成moc文件问题
    c++编译错误:invalid new-expression of abstract class type
    C++ 异常处理
    MATLAB 随机生成互不重叠的多个矩形
    sequential minimal optimization,SMO for SVM, (MATLAB code)
    How to decide on the correct number of clusters?
    python 将数据随机分为训练集和测试集
  • 原文地址:https://www.cnblogs.com/hl249853856/p/15204633.html
Copyright © 2011-2022 走看看