> 技术文档 > 【动态规划】二维费用的背包问题_二维费用背包

【动态规划】二维费用的背包问题_二维费用背包


二维费用的背包问题

  • 1.一和零
  • 2.盈利计划

在这里插入图片描述

点赞👍👍收藏🌟🌟关注💖💖
你的支持是对我最大的鼓励,我们一起努力吧!😃😃

1.一和零

题目链接: 474. 一和零

题目分析:

【动态规划】二维费用的背包问题_二维费用背包

找出并返回 strs 的最大子集的长度,该子集中 最多 有 m 个 0 和 n 个 1 ,也就说找到的子集 字符 0 的个数 小于等于 m,字符 1 的个数 小于等于 n。

【动态规划】二维费用的背包问题_二维费用背包

如果对背包问题敏感,这就是一个背包问题。背包问题问的是给一堆物品,让在这堆物品中选一些物品,在满足某个限定条件下,问一些东西,要么问最大价值,要么问多少种选法。。。。

这道题其实就是背包问题,就是在字符串数组中挑一些字符串出来,需要满足的是两个条件,字符 0 的个数小于等于5,字符 1 的个数小于等于3。像这种满足两个条件的背包问题,我们称之为二维费用背包问题。

二维费用背包问题:之前我们遇到的01背包问题,完全背包问题都只有一个限定条件,二维费用背包就是多了一个限制变成了两个限制条件。

二维费用背包问题也分为二维费用的01背包问题和二维费用的完全背包问题。

这这道题因为每个字符串都面临选or不选两种情况,所以是二维费用的01背包问题。

算法原理:

之前说过所有其余分类的背包问题都是从01背包问题哪里延申出来的。所以我们尝试用01背包问题分析思路来解决我们这里的问题。

1.状态表示

01背包状态表示:

dp[i][j] 表示:从前 i 个物品中挑选,总体积不超过 j,所有选法中,最大的价值

二维费用的01背包问题:其实就只是多加了一个限制条件,之前就只有体积限制,现在不仅有体积还有重量。所以多加一维。

dp[i][j][k] 表示:从前 i 个字符串中挑选,字符 0 的个数不超过 j,字符 1 的个数不超过 k,所有选法中,最长的长度。

【动态规划】二维费用的背包问题_二维费用背包

2.状态转移方程

本质还是一个01背包问题,所以我们还可以借用之前01背包状态转移方程的思路,根据最后一个位置,划分情况

设最后一个位置的字符串中,字符 0 的个数为 a,字符 1 的个数为 b。

不选 i 位置这个字符串,那就从 0 ~ i - 1 区间内字符串中挑,因为 i 位置都没选,所以0 ~ i - 1 区间内字符串中选 字符 0 的个数不超过 j,字符 1 的个数不超过k,在这两个限制条件下要的最大的长度。就是dp[i-1][j][k]

【动态规划】二维费用的背包问题_二维费用背包

选 i 位置这个字符串,整体要保证字符 0 的个数不超过 j,字符 1 的个数不超过k,又因为选了 i 位置这个字符串,接下去取 0 ~ i - 1挑的时候,就要去掉 i 这个字符串中 字符串 0 的个数 和 字符串 1 的个数。然后加上选 i 位置字符串的个数。

注意 j - a,k - b 不一定存在,所以用之前要判断一下。

【动态规划】二维费用的背包问题_二维费用背包

我们要的是最大长度,因此是两种情况的最大值

【动态规划】二维费用的背包问题_二维费用背包

如果01背包问题都熟悉了,二维费用的01背包问题就是多加一个限制条件其他都一样。

3.初始化

初始化和之前一样,仅需考虑 i = 0 的情况就可以了,k = 0,j = 0 我们会特判不会越界的。

当 i = 0 表示字符串数组里没有字符串,如果数组没有字符串,想凑成字符串 0 的个数不超过 j,字符串 1 的个数不超过 k ,根本不能做到,不能做到就是一个空集,如果是空集,那最大个数全都是0

【动态规划】二维费用的背包问题_二维费用背包

4.填表顺序

填dp[i][j][k]状态,要保证填 i 这一面 , i - 1 那一面的值已经填好了,因此仅需保证 i 从小到大。j、k无论怎么变化什么顺序都可以。

【动态规划】二维费用的背包问题_二维费用背包

5.返回值

dp[i][j][k] 表示:从前 i 个字符串中挑选,字符 0 的个数不超过 j,字符 1 的个数不超过 k,所有选法中,最长的长度。我们要的是从整个字符串中选,字符 0 的个数不超过 j,字符 1 的个数不超过 k,所有选法中,最长的长度。所以返回的是
dp[len][m][n],len是字符串数组长度。

class Solution { public: int findMaxForm(vector<string>& strs, int m, int n) {  int len = strs.size(); vector<vector<vector<int>>> dp(len + 1, vector<vector<int>>(m + 1, vector<int>(n + 1))); for(int i = 1; i <= len; ++i) {  //统计一下字符串中 0 1 的个数 int a = 0, b = 0; for(auto ch : strs[i - 1]) {  if(ch == \'0\') a++; else b++