• 【20221206】【每日一题】01背包的基础



    思路:

    二维数组

    动规五部曲

    1、确定dp数组以及下标含义:二维数组dp[i][j]表示从下标为0-i的物品里任意取,放入容量为j的背包,价值总和最大为多少
    2、确定递推关系式:从两个方向推dp[i][j],没放物品i以及放了物品i。没放物品i,由dp[i-1][j](当物品i的重量大于背包j的重量时,物品i无法放进背包中,所以被背包内的价值依然和前面相同),放了物品i,由dp[i-1][j-weight[i]]+value[i],也就模拟了物品i放入后得到的价值。因此递推关系式为:dp[i][j]=max(dp[i-1][j],dp[i-1][j-weight[i]]+value[i])
    3、初始化:背包容量为0时,一定为0;由递推关系可知i状态的价值由i-1状态推导而来,所以物品0的状态都需要初始化,即dp[0][j]。
    4、确定遍历顺序:有两种遍历维度,物品与背包重量,先遍历物品更好理解。
    5、举例推导dp数组。

    1. void test() {
    2. vector<int> weight = { 1,3,4,1 };
    3. vector<int> value = { 15,20,40,25};
    4. int bagweight = 4;
    5. //初始化
    6. vectorint>> dp(weight.size(), vector<int>(bagweight + 1, 0));
    7. for (int i = weight[0]; i <= bagweight; i++)
    8. {
    9. dp[0][i] = value[0];
    10. }
    11. //两个维度的遍历,先遍历物品,再遍历背包
    12. for (int i = 1; i < weight.size(); i++)
    13. {
    14. for (int j = 1; j <= bagweight; j++)
    15. {
    16. if (j < weight[i]) dp[i][j] = dp[i - 1][j];//物品i没放进来
    17. else dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]);
    18. }
    19. }
    20. cout << dp[weight.size() - 1][bagweight] << endl;
    21. }
    22. int main()
    23. {
    24. test();
    25. }

    滚动数组

    如果将dp[i-1]那层的数据都拷贝到dp[i]那一层,递推公式其实可以变为:dp[i][j]=max(dp[i][j],dp[i][j-weight[i]]+value[i])。
    只用一个一维数组来实现,即滚动数组。能用滚动数组的条件是:上一层可以重复利用,直接拷贝到当前层。

    动规五部曲
    1、dp数组的意义:dp[j]表示容量为j的背包最大价值为dp[j]
    2、递推关系式:dp[j]可以通过dp[j-weight[i]]推导,dp[j]=max(dp[j],dp[j]-weight[i]+value[i])
    3、初始化:如果价值都大于0的话,刚开始的时候都初始化为0即可。
    4、确定遍历顺序:先物品再背包,注意这里遍历背包的时候是从大到小倒序的目的是为了保证物品i只被放入了一次,从后往前循环,每次取得状态不会和之前取得状态重合,这样每种物品就只取一次了。 注意终止条件:for(int j = bagWeight; j >= weight[i]; j--)
    5、举例推导dp数组。

    1. void test01() {
    2. vector<int> weight = { 1,3,4,1 };
    3. vector<int> value = { 15,20,40,25 };
    4. int bagweight = 4;
    5. //初始化
    6. vector<int> dp(bagweight + 1, 0);
    7. for (int i = 0; i < weight.size(); i++)
    8. {
    9. for (int j = bagweight; j >= weight[i]; j--)//背包倒序
    10. {
    11. dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);
    12. }
    13. for_each(dp.begin(), dp.end(), [=](int x) {cout << x << " "; });
    14. cout << endl;
    15. }
    16. //cout << dp[bagweight] << endl;
    17. }
    18. int main()
    19. {
    20. test01();
    21. }

    将每一次都打印出来,其实发现和二维数组是一样的,节省了空间复杂度。 

     

     

  • 相关阅读:
    常用H标签的补充:html5
    Ubuntu离线或在线安装Python解释器
    空间变换矩阵的三种理解方式
    Java之转换流的详细解析
    面试官这一套 Framework 连环炮;看看你能撑到第几步?
    【MCAL_CANDriver】-1.4-Tq与Bit Rate,Sync_Seg,Prop_Seg,Phase_Seg1, Phase_Seg2之间的关系
    VRRP基础
    【第26天】给定 n 个元素的升序数组nums,求实现一个函数在nums中寻找target的下标 | 初识二分查找
    SPI_OLED模块操作方法
    spring boot项目运行及打包
  • 原文地址:https://blog.csdn.net/HYAIWYH/article/details/128209573