每日一题--多属性的01背包问题

Posted C_YCBX Py_YYDS

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了每日一题--多属性的01背包问题相关的知识,希望对你有一定的参考价值。

题目

在这里插入图片描述

题目详解

什么是多属性的背包问题?比如对于这道题,它可以看作是一个具有装下物品两个属性的背包(装下0和1),它的容量可以看作是[j][k]可用二维数组来表示,而外面一层和普通的01背包问题一样,用于表示在有多少个物体的情况下装下物体的个数

  • 那么dp数组定义如下–dp[i][j][k]表示给出前i个物体,并且背包容量为[i][k](装下1和0的容量)的情况下所能装下的最多物体,由于对于每个物体是一个字符串,每个字符串有0或者1两种属性,可设计一个函数用于专门求0和1 的个数
  • 对于此题dp关系为:dp[i][j][k] = dp[i-1][j][k](no pack)+dp[i-1][j-count(0)][k-count(1)](pack).
  • 最后由于是背包问题base case肯定是背包容量为0以及给出物品数为0的情况,即dp[0][..][..] = 0,dp[..][0][0] = 0,根据三维空间画图可知遍历方向是从左往右从下往上.

三维空间实现多属性01背包

class Solution {
public:
//三维数组实现dp关系
//用于计数每个字符串的0和1用长度为2的数组返回
    vector<int> getZerosOnes(string& str) {
        vector<int> zerosOnes(2);
        int length = str.length();
        for (int i = 0; i < length; i++) {
            zerosOnes[str[i] - '0']++;
        }
        return zerosOnes;
    }

    int findMaxForm(vector<string>& strs, int m, int n) {
        int length = strs.size();
        //三维vector数组
        vector<vector<vector<int>>> dp(length + 1, vector<vector<int>>(m + 1, vector<int>(n + 1)));//最外面一层是表示放入前i个物品后,背包容量为j和k的最多容量(最多放几个物品,通过每个物品的放与不放来枚举得到)本质上是一个三维的01背包问题
        for (int i = 1; i <= length; i++) {
            //右值引用得到函数返回值,减少空间消耗
            vector<int>&& zerosOnes = getZerosOnes(strs[i - 1]);
            int zeros = zerosOnes[0], ones = zerosOnes[1];
            for (int j = 0; j <= m; j++) {
                for (int k = 0; k <= n; k++) {
                    dp[i][j][k] = dp[i - 1][j][k];
                    if (j >= zeros && k >= ones) {
                        dp[i][j][k] = max(dp[i-1][j][k], dp[i - 1][j - zeros][k - ones] + 1);
                    }
                }
            }
        }
        return dp[length][m][n];
    }
};

滚动数组到二维空间

由于每个结果只和上一行的结果有关,故可直接优化。
由于要保证每个为上一行的结果,此时需要背包逆向遍历。

class Solution {
public:
    vector<int> getZerosOnes(string& str) {
        vector<int> zerosOnes(2);
        int length = str.length();
        for (int i = 0; i < length; i++) {
            zerosOnes[str[i] - '0']++;
        }
        return zerosOnes;
    }

    int findMaxForm(vector<string>& strs, int m, int n) {
        int length = strs.size();
        vector<vector<int>> dp(m + 1, vector<int>(n + 1));
        for (int i = 0; i < length; i++) {
            vector<int>&& zerosOnes = getZerosOnes(strs[i]);
            int zeros = zerosOnes[0], ones = zerosOnes[1];
            //背包容量逆向遍历
            for (int j = m; j >= zeros; j--) {
                for (int k = n; k >= ones; k--) {
                    dp[j][k] = max(dp[j][k], dp[j - zeros][k - ones] + 1);
                }
            }
        }
        return dp[m][n];
    }
};

以上是关于每日一题--多属性的01背包问题的主要内容,如果未能解决你的问题,请参考以下文章

4.6 每日一题题解

每日一题(一和零),转化为二维动态规划问题题解

2021春季每日一题week6 未完结

寒假每日一题(入门组)week3 完结

LeetCode 1024. 视频拼接(每日一题)

JAVA找到处理最多请求的服务器——力扣每日一题(2022.03.30)