• 动态规划


    概念

      动态规划也是一种分治思想,但是与分治法不同,动态规划把原问题分解为若干子问题,然后自底向上,先求解最小的子问题,把结果存储在表格中,再求解大的子问题时,直接从表格中查询小的子问题的解,最终得到原问题的解。

    能利用动态规划解决的问题有2个特性

    1.最优子结构

      问题的最优解包含其子问题的最优解

    2.子问题重叠

      大的子问题求解时需要用到小的子问题的解,所以每次求得子问题的解时,把它们放在表格里,以后使用时可以直接查询

    使用动态规划的步骤

    1.分析最优解的结构特征

    2.建立最优值的递归式(最为关键)

    3.自底向上计算最优值,并记录到表格里

    4.得出最优解

    例子1——0-1背包问题

    问题描述:

      背包载重为load,山洞中有n个宝贝,每个宝贝的重量为wi,价值为vi,每个宝贝要么装入要么不装入,盗贼能盗取的最大价值是多少?

    确定数据结构:

      weight[i]:第i个物品的重量

      value[i]:第i个物品的价值

      dp[i][j]:前i件物品放入总载重为j的购物车可获得的最大价值

      choose[i]:是否选择了第i件物品

    递归式:

      dp[i][j]=  dp[i-1][j]                  , j<weight[i]

            max(dp[i-1][j], dp[i-1][j-weight[i]]+value[i])  , j>=weight[i]

    我们一件物品一件物品得选择放与不放,如果背包的总载重小于第i件物品的重量,我们就只能依靠前一个子问题的值;如果大于,我们就可以选择前一个子问题的值和加上了第i件物品的价值的值中的较大值。可能疑惑的是:为什么拿背包的总载重去和当前这个物品的重量去比,难道不用考虑之前已经装入背包的物品的重量吗?其实这个值dp[i-1][j-weight[i]]是有可能是0的。j和weight[i]去比,你可以理解为是防止这个数组的访问不越界。

    自底向上计算:

      初值dp[0][j]和dp[i][0]从所代表的意义上可以得出,其值均为0。

    得出最优解:

      n个物品,背包总载重为m,最大价值就为dp[n][m];

      确定选择了哪些物品:比较dp[n][m]和dp[n-1][m]的大小,如果相等,则代表没有选择第n个物品,choose[n]置为false,否则,置为true;如果选择了选择第n个物品,则跳到dp[n-1][m-weight[n]](如果没有选择,则跳到dp[n-1][m]),再进行相同的操作,直至每个物品都检查完。

    代码实现:

     1 int zeroOneBag(vector<int>& weight, vector<int>& value, int load, vector<bool>& choose)
     2 {
     3     int n = weight.size() - 1;//物品的数量n,重量数组和价值数组的第0个元素均为0
     4     vector<vector<int>> dp(n + 1, vector<int>(load+1));
     5     for (int i = 0; i <= n; ++i)
     6         dp[i][0] = 0;
     7     for (int j = 0; j <= load; ++j)
     8         dp[0][j] = 0;
     9     for (int i = 1; i <= n; ++i)
    10     {
    11         for (int j = 1; j <= load; ++j)
    12         {
    13             if (j < weight[i])
    14                 dp[i][j] = dp[i - 1][j];
    15             else
    16                 dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]);
    17         }
    18 
    19     }
    20     /*
    21     for (int i = 0; i <= n; ++i)//展示dp数组
    22     {
    23         for (int j = 0; j <= load; ++j)
    24         {
    25             cout << dp[i][j] << '	';
    26         }
    27         cout << endl;
    28     }
    29     */
    30     for (int i = n, j = load; i >= 1; --i)
    31     {
    32         if (dp[i][j] > dp[i - 1][j])
    33         {
    34             choose[i] = true;
    35             j -= weight[i];
    36         }
    37         else
    38             choose[i] = false;
    39     }
    40     /*
    41     for (int i = 1; i <= n; ++i)//展示选择了哪些物品
    42         cout << choose[i] << '	';
    43     cout << endl;
    44     */
    45     return dp[n][load];
    46 }

    测试例:

     1 int main()
     2 {
     3     vector<int> weight{ 0,2,5,4,2,3 }, value{ 0,6,3,5,4,6 };
     4     vector<bool> choose(6);
     5     int load=10;    
     6     int maxiValue=zeroOneBag(weight, value, load, choose);
     7     cout << "0-1背包所能装的最大价值为:"<<maxiValue << endl;
     8 
     9     return 0;
    10 }

  • 相关阅读:
    maven项目打ZIP包
    springBoot文档地址
    延迟队列DelayQueue
    图片处理依赖
    java模板引擎替换代码
    redisson笔记
    linux 自动备份脚本
    shell 远程备份日志
    amqp事务
    redis 事务
  • 原文地址:https://www.cnblogs.com/Joezzz/p/9683854.html
Copyright © 2020-2023  润新知