代码随想录算法训练营第三十六天-动态规划-474.一和零

  • 背包问题本身就已经够反思维的了,竟然物品会有两个维度的情况,这是闹哪样?
  • 题目要求是最大子集的个数
  • 题目中的 m m m n n n可以类比为容器,要装潢这个容器,最多要多少个元素的个数,就是结果,这个容器最多有 m m m个0, n n n个1
  • 这个容器相当于一个背包,这个背包是有两个维度,最多有 m m m个0, n n n个1,装潢这个背包最多需要多少个物品
  • 给出的数据集就是物品
  • 这是一道01背包问题
  • 动规五部曲
    • 这里要使用一个二维的动规数组,dp[i][j]表示i个0,j个1容量的背包最多装了多少个物品
    • 递推公式:dp[i][j]=std::max(dp[i][j], dp[i-x][j-y]+1),这其中的xy表示当前物品的有x个0,y个1
      • 为什么要加1呢,这是因为要把当前物品加入到子集中,所以子集元素的数量就增加了1
    • 递推公式的初始化:要将初始化值都设为0,因为这个是一个纯的01背包问题
      • 这里与上一道题的初始化看似一致,但为什么要设置初始值为0,而不是1呢。解释一下
      • 在上一题中,可以在集合中添加一个0元素,这个元素只对初始值的设定来添加的,因为可以添加这个元素,从而导致dp[0]=1是成立的,也不影响最终结果
      • 而本题中是不能添加0元素的,因为0元素相当于是一个1个0,0个1的物品,是影响最终结果的元素,因此就没有这样的元素来装入dp[0][0]这个背包中,自然值就是0了
      • 而且递推公式中有加1,所以不会担心递推后所所有的值都是0了
    • 遍历:物品正序遍历,容量倒序遍历
      • 容量倒序遍历是因为保证每个物品只会添加一次
    • 打印
for (std::string s: strs) {
    int x = 0, y = 0;
    for (char c: s) {
        if (c == '0')
            ++x;
        else
            ++y;
    }
    for (int i = m; i >= x; --i) {
        for (int j = n; j >= y; --i)
            dp[i][j] = std::max(dp[i - x][j - y] + 1, dp[i][j]);
    }
}
问题描述 解决问题 特征
纯01背包 给定容器,问装满容器后的最大价值
分割等和子集 给定容器(全集和的一半容量),问题是能不能装满这个容器 最大价值能不能等于背包容量
最后一块石头重量 给定容器(全集和的一半容量),尽量将其装满,最多能装多少 求最大价值值
目标和 给定容量,装满这个背包有多少种方法
一和零 装满一个指定容器(有两个维度),最多有多少个物品
  • 汇总

你可能感兴趣的:(算法,动态规划,c++,leetcode)