Yiwen church 01 Backpack

Posted by kate_rose on Mon, 24 Jan 2022 21:49:08 +0100

01 Backpack

01 backpack refers to a topic template

If there are many things, each thing can only be loaded into a backpack once, and the backpack has an upper volume limit

This is the classic 01 knapsack problem

When we subconsciously recite the template

Let's first think about the violent solution to the 01 knapsack problem

In the 01 backpack, each item is either taken or not taken, so there are 2^n cases in total

This is the practice of backtracking + explosive search

In order to optimize the time complexity, we introduce dynamic programming (DP)

To explain dynamic programming

I decided to introduce the concept of a DP Trilogy (from code Capriccio)

  • Determine the meaning of dp array (dp table) and subscript
  • Determine recurrence formula
  • How to initialize dp array
  • Determine traversal order
  • Example derivation dp array

The following is the template question of 01 backpack

There are N items and a backpack with a capacity of V. Each item can only be used once.

The volume of article i is vi and the value is wi

Solve which items are loaded into the backpack, so that the total volume of these items does not exceed the backpack capacity, and the total value is the largest. Output maximum value.

Input format

The first line contains two integers, N and V, separated by spaces, representing the number of items and the volume of the backpack respectively.

Next, there are N lines, with two integers VI and WI in each line, separated by spaces, representing the volume and value of the i-th article respectively.

Output format

Output an integer representing the maximum value.

Data range

0 < N , V ≤ 1000 0<N,V≤1000 0<N,V≤1000

0 < v i , w i ≤ 1000 0<vi,wi≤1000 0<vi,wi≤1000

sample input

4 5
1 2
2 4
3 4
4 5

Output example:

8

The simple approach is like this

 	int n, V;
    cin >> n >> V;
    for(int i = 1; i <= n; i++) cin >> v[i] >> w[i];
    
    for(int i = 1; i <= n; i++)
    	for(int j = 1; j <= V; j++)
    	{ 
    		if(j >= v[i])	dp[i][j] = max(dp[i-1][j], dp[i-1][j-v[i]] + w[i]);
    		else	dp[i][j] = dp[i-1][j];
    	}
    	
    cout << dp[n][V] << endl;

For the knapsack problem, the state can be compressed

When using a two-dimensional array, the recursive formula is:
dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]);
In fact, we found that if dp[i-1]Copy that layer directly to dp[i] The expression can be:
dp[i][j] = max(dp[i][j], dp[i][j - weight[i]] + value[i]);

One dimensional method after compression

 	int n, V;
    cin >> n >> V;
    for(int i = 1; i <= n; i++) cin >> v[i] >> w[i];
    
    for(int i = 1; i <= n; i++)
    	for(int j = V; j >= w[i]; j--)
            dp[j] = max(dp[j], dp[j - w[i]] + value[i]);
    cout << dp[V] << endl;

We performed a DP five part analysis on 01 backpack

1. Determine the definition of dp array

In the one-dimensional dp array, dp[j] represents the maximum value of the item carried when the volume is j

2. Recurrence formula

dp[j] = max(dp[j],  dp[j - weight[i]] + value[j]);

3. Initialization of array

With regard to initialization, we should consider points 1 and 2. In practical problems, we usually think about 3 and 4 together

Because dp[j] means that the maximum value of a backpack with a capacity of j is dp[j]

Then when j = 0, nothing can be installed. dp[0] = 0;

Let's look at the recursive formula

Because the meaning of dp array is the maximum value, when the value is not negative, the non-0 subscript can be initialized to 0

However, when the value is negative, the non-zero subscript must be initialized to negative infinity, otherwise the initial value will cover the maximum value

//How cpp initializes an array to negative infinity
memset(d, 0x8f, sizeof(d));

4. Order of array traversal

Different from some linear DP problems, knapsack problem does not directly give the recursive direction in the recursive formula

for(int i = 1; i <= n; i++)
	for(int j = V; j >= w[i]; j--)
		dp[j] = max(dp[j], dp[j-w[i]] + value[i]);

Here we suddenly find that the traversal writing method of rolling array is somewhat different from that of two-dimensional array

Why is the loop order of the embedded loop from large to small?

A: the reverse order traversal is to ensure that each item is only put into the backpack once

There may be some difficulties here

Let's take an example: weight w[0] = 1, value[0] = 15;

Positive order traversal:

dp[1] = dp[1 - weight[0]] + value[0] = 15
dp[2] = dp[2 - weight[0]] + value[0] = 30

Item 0 has been added twice. How could it be?

Traversal in reverse order:

dp[2] = dp[2 - weight[0]] + value[0] = 15 (dp Array already initialized to 0)
dp[1] = dp[1 - weight[0]] + value[0] = 15

When traversing from back to front, the status obtained each time will not overlap with the status obtained before, so as to ensure that each item is added once

Then the question comes again. Why don't you need to traverse in reverse order in a two-dimensional array?

Because dp[i] [j] in the two-dimensional array is obtained through dp[i-1] [j], the of this layer will not be covered

It's difficult to speak here. It's recommended to practice to get real knowledge

Let's take a look at the order of the two nested for loops. In the code, we first traverse the items nested and traverse the backpack capacity. Can we traverse the backpack capacity nested and traverse the items first?

Da baa!

Because of the writing of one-dimensional dp, the backpack capacity must be traversed in reverse order (the reason has been mentioned above). If the traversed backpack capacity is placed on the upper layer, each dp[j] will only put one item, that is, only one item is placed in the backpack.

If you can't understand it, it is recommended to reverse the for loop and output the dp array for observation

5. Example derivation

Weight value
Item 0 1 15
Item 1 3 20
Item 2 4 30

One dimensional dp, use item 0, item 1 and item 2 to traverse the backpack respectively, and the final results are as follows:

First traversal of item 0 0 | 15 | 15 | 15 | 15

Traverse item 1 0 | 15 | 15 | 20 | 35 for the second time

Traverse item 20 | 15 | 15 | 20 | 35 for the third time

Topics: Algorithm leetcode Dynamic Programming