"Algorithms that programmers must master" Dynamic Programming "Part 1"

Detailed explanation of dynamic programming

Dynamic Programming is an algorithmic idea used to solve some complex problems. This article will introduce the classification, concepts and classic examples of dynamic programming.

Classification of dynamic programming

Dynamic programming can be divided into the following two types:

  1. 0/1 knapsack problem: This problem is a basic type of dynamic programming. In the knapsack problem, there are n items that can be put into a knapsack with capacity W. Each item has its own weight and value. You need to choose which items maximize the total value of your backpack.
  2. Longest common subsequence problem: This problem is another classic type of dynamic programming that involves two strings and finding the longest common subsequence between the two strings.

The concept of dynamic programming

When solving dynamic programming problems, we need to define the following concepts:

  1. State: Variables that need to be optimized in the problem, such as capacity in the knapsack problem, string length in the longest common subsequence problem, etc.
  2. State Transition Equation: describes the transition process between states, that is, the recursion relationship of the problem. For example, in the knapsack problem, each item can be put into the knapsack or not. Therefore, the state transition equation can be expressed as: dp [ i ] [ j ] = max ⁡ ( dp [ i − 1 ] [ j ] , dp [ i − 1 ] [ j − wi ] + vi ) dp[i][j ] = \max(dp[i-1][j], dp[i-1][j-w_i]+v_i)dp[i][j]=max(dp[i1][j],dp[i1][jwi]+vi) where dp[i][j] represents the maximum value of a backpack filled with j capacity when using the first i items.
  3. Initial State: The initial condition of the problem, usually the answer when the problem is smallest. In the knapsack problem, the initial state is dp[0][0]=0.
  4. Boundary State: Boundary conditions of the problem, states that require special treatment during the state transition process. In the knapsack problem, the capacity of the knapsack cannot be negative, so special treatment is required in the state transition equation.

Explanation of classic examples

Below we will introduce the solutions to the 0/1 knapsack problem and the longest common subsequence problem respectively.

1. 0/1 backpack problem

Problem description: There are n items and a backpack with a capacity of W. The i-th item has a weight wi and a value vi. Now, you need to select some items to put into the backpack so that the total weight of the items placed does not exceed W and the total value is the largest. Seek maximum value.

Problem-solving idea: Define state dp[i][j] as the maximum value of a backpack filled with j capacity when using the first i items. The state transition equation is as follows: dp [ i ] [ j ] = { dp [ i − 1 ] [ j ] , j < wi max ⁡ ( dp [ i − 1 ] [ j ] , dp [ i − 1 ] [ j − wi ] + vi ) , j ≥ wi dp[i][j] = \begin{cases}dp[i-1][j],&j<w_i\\ \max(dp[i-1][j] , dp[i-1][j-w_i]+v_i),&j\ge w_i\end{cases}dp[i][j]={ dp[i1][j],max(dp[i1][j],dp[i1][jwi]+vi),j<wijwiAmong them, dp[i-1][j] represents the maximum value of the i-th item without adding it, and dp[i-1][jw[i]]+v[i] represents the maximum value of the i-th item added to the backpack. . It should be noted that if the current backpack capacity is less than the weight of the item, the item cannot be put into the backpack. Therefore, special handling is required when the backpack capacity is less than the weight of the items.

Code:

int dp[101][1001];
int weight[101], value[101];

int knapSack(int n, int w)
{
    memset(dp, 0, sizeof(dp));
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= w; j++) {
            if (j < weight[i]) {
                dp[i][j] = dp[i-1][j];
            } else {
                dp[i][j] = max(dp[i-1][j], dp[i-1][j-weight[i]]+value[i]);
            }
        }
    }
    return dp[n][w];
}

2. Longest common subsequence problem

Problem description: Given two strings A and B, find their longest common subsequence (LCS).

Problem-solving idea: Define state dp[i][j] as the LCS length of the first i characters of string A and the first j characters of string B. The state transition equation is as follows:

d p [ i ] [ j ] = { 0 , i = 0 或 j = 0 d p [ i − 1 ] [ j − 1 ] + 1 , A i = B j max ⁡ ( d p [ i − 1 ] [ j ] , d p [ i ] [ j − 1 ] ) , A i ≠ B j dp[i][j] = \begin{cases}0,&i=0\text{或}j=0\\ dp[i-1][j-1]+1,&A_i=B_j\\ \max(dp[i-1][j], dp[i][j-1]),&A_i\neq B_j\end{cases} dp[i][j]= 0,dp[i1][j1]+1,max(dp[i1][j],dp[i][j1]),i=0 or j=0Ai=BjAi=Bj

When A[i-1] is equal to B[j-1], dp[i][j] is equal to dp[i-1][j-1]+1, indicating that the same characters in A and B plus their preceding LCS. When they are not equal, the LCS is the maximum value of the LCS before them, that is, the maximum value of dp[i-1][j] and dp[i][j-1].

Code:

int dp[1001][1001];
string A, B;

int LCS(int n, int m)
{
    for (int i = 0; i <= n; i++) {
        for (int j = 0; j <= m; j++) {
            if (i == 0 || j == 0) {
                dp[i][j] = 0;
            } else if (A[i-1] == B[j-1]) {
                dp[i][j] = dp[i-1][j-1] + 1;
            } else {
                dp[i][j] = max(dp[i-1][j], dp[i][j-1]);
            }
        }
    }
    return dp[n][m];
}

Conclusion

Dynamic programming is a very important algorithmic idea, which is often used to solve complex problems. When applying dynamic programming to solve problems, you need to pay attention to concepts such as defined states, state transition equations, initial states, and boundary states. Different types of dynamic programming problems require different solutions. I hope this article can help readers deepen their understanding of dynamic programming.

Guess you like

Origin blog.csdn.net/qq_45704048/article/details/132791716