Detailed explanation of grouped backpacks, detailed explanation of common issues, complete code attached

Preface

Grouping backpacks is an advanced problem of 01 backpack. It is basically similar to the idea of ​​01 backpack. It is the simplest type of problem among advanced backpack problems, but the difficulty lies in its derivative problems. Pay attention to the difference between the grouped backpack and the 01 backpack, and understand the meaning of the state transition equation instead of memorizing the board.


Problem introduction

There are n items and a backpack with capacity v. These items are divided into m groups. The j-th item in the i-th group has a volume of c[i][j] and a value of w[i][j]. The items in each group conflict with each other, and at most one is selected. Find which items can be packed into a knapsack so that the sum of their volumes does not exceed the knapsack capacity and the sum of their values ​​is maximum.

It can be seen that the only difference between the 01 backpack and the 01 backpack is that the maximum number of items you can take is one item per group of items. Since the maximum number of items you can take is one item, there is no limit like the full backpack with multiple backpacks. The difficulty of the problem has not actually increased much. .

Algorithm principle

state design

The problem becomes how many strategies there are for each group of items, which means that we can choose one item per group or not. We might as well define the state dp[i][j] as the first i group of items (each group can choose at most one) exactly The maximum value that can be put into a backpack with capacity j.

state transition equation

Again, there are two options for each item:

  • Put: Put the k-th item belonging to the i-th group into a backpack with a capacity of j, then the problem is transformed into "Put the first i - 1 group of items (select at most one from each group) into a backpack with a capacity of j - c[i][k" ]'s backpack" problem, the maximum value at this time is "the maximum value of the first i - 1 groups of items (choose at most one from each group) that happens to be put into a backpack with a capacity of j - c[i][k] plus w[ i][k]”
  • Do not put: The k-th item belonging to the i-th group is not put into the knapsack with capacity j, then the problem is transformed into the problem of "Put the first i - 1 group of items (select at most one from each group) into the knapsack with capacity j" , the maximum value at this time is "the maximum value of the first i - 1 groups of items (choose at most one from each group) that happens to be put into a backpack with capacity j"

Then there is a state transition equation:
dp [ i ] [ j ] = max ( dp [ i − 1 ] [ j ] , dp [ i − 1 ] [ j − c [ i ] [ k ] ] + w [ i ] [ k ] ) dp[i][j] = max(dp[i - 1][j] , dp[i - 1][j - c[i][k]] + w[i][k])dp[i][j]=max(dp[i1][j],dp[i1][jc[i][k]]+w[i][k])

Time complexity analysis

For a backpack with n items and capacity v, there are obviously O(n*v) states, and the cost of each state transfer is O(1), so the time complexity is O(nv)

Note that our calculation of time complexity here is based on the number of items rather than the number of groups, and the state transfer cost is O(1).

2D Naive Code

vector<vector<int>> dp(m + 1 , vector<int>(v + 1));
for (int i = 1; i <= n; i++)
    for (int j = v; j >= 0; j--)
        for (int k = (dp[i][j] = dp[i - 1][j] , 0) ; k < c[i].size() ; k++)
            dp[i][j] = max(dp[i][j] , dp[i - 1][j - c[i][k]] + w[i][k]);

Rolling array optimization

Our first i group of state transfers are still only related to the previous i - 1 group, and each specific state is only related to the state in the upper left rectangular area of ​​​​the state table. Therefore, we can still optimize the two-dimensional to one-dimensional, then there is a state transfer Equation
dp [ j ] = max ( dp [ j ] , dp [ j − c [ i ] [ k ] ] + w [ i ] [ k ] ) dp[j] = max(dp[j] , dp[j - c[i][k]] + w[i][k])dp[j]=max(dp[j],dp[jc[i][k]]+w[i][k])

One-dimensional optimized code

vector<int> dp(v + 1);
for (int i = 1; i <= n; i++)
    for (int j = v; j >= 0; j--)
        for (int k = 0; k < c[i].size() ; k++)
            dp[j] = max(dp[j] , dp[j - c[i][k]] + w[i][k]);

OJ Lectures

Number of plans

1155. The number of ways to roll a dice equal to the target sum

First abstract the grouping knapsack problem. Each die can be regarded as a group, and each face is a member of the group. Then we have n groups, n*k items, and find the maximum number of options that fit into the target capacity backpack.

Define dp[i][j] as the maximum number of options that the first i group can put into a backpack with capacity j, then there is a recursion
dp [ i ] [ j ] = ∑ dp [ i − 1 ] [ j − x ] , j > = x and x < = k dp[i][j] = \sum dp[i - 1][j - x],j >= x and x <= kdp[i][j]=dp[i1][jx],j>=x and x<=k
is obviously 1 for the initial state dp[0][0]

Then just run the board

The one-dimensional optimization code is as follows:

class Solution {
public:
const int mod = 1e9 + 7;
    int numRollsToTarget(int n, int k, int target) {
        vector<int> dp(target + 1);
        dp[0] = 1;
        for(int i = 1 ; i <= n ; i++)
            for(int j = target ; j >= 0 ; j--)
            {
                dp[j] = 0;
                for(int x = 1 ; j >= x && x <= k ; x++)
                    dp[j] = (dp[j] + dp[j - x]) % mod;
            }
        return dp[target];
    }
};

Is the plan feasible?

1981. Minimize the difference between the target value and the selected element

For this question, each row of the matrix is ​​a group. What we require is that each group must choose one, and the absolute minimum value of the difference between the total weight and the target is obtained.

This is not a question of seeking the best value, but of seeking the feasibility of the solution.

We can find all possible final weights and then iterate and maintain the minimum absolute difference.

Define dp[i][j] as the first i group. Is it feasible for each group to put exactly one into a backpack with capacity j?

那么有
d p [ i ] [ j ] = d p [ i ] [ j ] ∣ d p [ i − 1 ] [ j − c [ k ] ] dp[i][j] = dp[i][j]|dp[i - 1][j - c[k]] dp[i][j]=dp[i][j]dp[i1][jc [ k ]]
state initialization dp[0][mat[0][i]] = 1, then run the board

The code here takes advantage of the bit operation characteristics of bitmaps, and can also be replaced by vectors.

class Solution {
public:
    int minimizeTheDifference(vector<vector<int>>& mat, int target) {
        bitset<5000> dp[71];
        int m = mat.size() , n = mat[0].size();
        
        for(int i = 0 ; i < n ; i++) dp[0][mat[0][i]] = 1;
        for(int i = 1 ; i < m ; i++)
        {
            for(int j = 0 ; j < n ; j++)
                dp[i] = dp[i] | (dp[i - 1] << mat[i][j]);
        }
        int ret = 10000;
        for(int i = 0 ; i < 4901 ; i++)
        if(dp[m - 1][i]) ret = min(ret , abs(i - target));
        return ret;
    }
};

Rolling array optimization

Since bitmap space overhead is extremely small, using smart pointers to scroll array optimization does not significantly improve space utilization. On the contrary, there is a slight performance decrease because every time it is set to 0

class Solution {
public:
#define bs bitset<4901>
    int minimizeTheDifference(vector<vector<int>>& mat, int target) {
        auto dp = make_unique<bs>(1) , cur = make_unique<bs>();
        for(auto& x : mat){
        for(auto& y : x) *cur |= *dp << y;
        swap(cur , dp);
        *cur = 0;
        }
        int res = 4901;
        for(int i = 0 ; i < 4901 ; i++)
        if((*dp)[i])
        res = min(res , abs(i - target));
        return res;
    }
};

maximum value

2218. Remove the maximum face value sum of K coins from the stack

How to abstract the grouped knapsack problem?

Obviously k stacks are k groups, but the items in the group are not each element of the stack, but the prefix sum of the stack, so that the volume of the items becomes the length of the prefix sum.

Then it became a group backpack naked question

The one-dimensional optimization code is as follows:

class Solution {
public:
    int maxValueOfCoins(vector<vector<int>>& piles, int k) {
        int m = piles.size() , n;
        vector<int> dp(k + 1);

        for(int i = 1 ;i <= m ; i++)
        {
            n = piles[i - 1].size();
            for(int x = 1 ; x < n ; x ++)
                piles[i - 1][x] += piles[i - 1][x - 1];
            for(int j = k ; j >= 0 ; j--)
                for(int x = 0 ; x + 1 <= j && x < n ; x++)
                    dp[j] = max(dp[j] , dp[j - x - 1] + piles[i - 1][x]);
        }
        return dp[k];
    }
};

Summarize

Through three simple examples, we can also feel that the board is actually not difficult. Many times the questions are not so straightforward and directly divide you into groups. Sometimes there are even no items. This requires us to understand the algorithm itself and be able to put it into practice. Specific problems are abstracted into familiar problems and then solved.

The grouped backpack itself is relatively easy to understand, but it will be the basis for dependent backpacks, tree DP, and grouped backpacks on the tree.

Guess you like

Origin blog.csdn.net/EQUINOX1/article/details/135200076