Dynamic Programming (DP)

main idea

When solving a difficult problem, the problem is decomposed into discrete sub-problems, by first solving the sub-problems, and then gradually solving the big problem.

Similarities and differences with divide and conquer algorithm

  • Similarities: The basic idea of ​​both is to decompose the problem to be solved into several sub-problems, first solve the sub-problems, and then obtain the solution of the original problem from the solutions of these sub-problems.
  • Difference: The sub-problems decomposed by divide-and-conquer algorithms are often independent and have nothing to do with each other, such as quick sort. The sub-problems obtained by dynamic programming decomposition are often not independent of each other, that is, the next sub-problem is often solved on the basis of the previous sub-problem.

Classic problem 1-01 knapsack problem

If you are a thief, carrying a backpack that can hold 4 pounds, there are three kinds of goods you can steal:
1) Audio ($3,000, 4 pounds)
2) Laptop ($2,000, 3 pounds)
3) Guitar ($1,500, 1 pound)
In order to make the stolen goods more valuable, which goods should you choose? What is the value?

1. The simple way

Try various possible product combinations and find the combination with the highest value. 3 items of 2 3 2^32Three kinds of combination methods, it can be seen that when the types of goods increase, this method is very slow, and the time complexity isO (2 n) O(2^n)O ( 2n)

2. Greedy Algorithm

For each selection, choose the product with the highest unit price that meets the conditions. We can find an approximate solution with less overhead. In this question, the final result of using the greedy algorithm is "sound", but the approximate solution is not necessarily the optimal solution. The actual stolen product value is the "laptop + guitar".

3. Dynamic programming

When solving the problem of a 4-pound capacity backpack, we can first solve the problem of a 3-pound capacity backpack, 2 pounds..., 1 pound.... Simplify the problem of choosing the highest value from 3 things into 2 things..., 1 thing.... By solving the sub-problems, the original big problem is solved step by step.

Every dynamic programming algorithm starts with a grid, and the grid of the knapsack problem is as follows.
Insert picture description here
We only need to fill the table row by row (or column by column from left to right) from top to bottom. When the table is filled, we get the answer to the question.

  • Guitar shop: Because the only thing that can be stolen is the guitar, and the weight of the guitar is 1 pound, so the guitar shop should add "guitar, 1,500 US dollars".
  • Audio line: The audio weight is 4 pounds, so the first 3 grids can still only steal the guitar, because the value of the audio is higher than the guitar, so the fourth grid adds "audio, $3,000".
  • Notebook computer line: Because the laptop weight is 3 pounds, the first two grids remain the same, and they are still guitars. The third grid is because the price of the laptop is higher than the guitar, so add a laptop, the fourth grid , Because laptops and guitars are more expensive than speakers, so you should add "laptops, guitars, $3,500", which is the answer to this question.

The final grid should look like the image below.
Insert picture description here
Through the above analysis, we can calculate the value of each grid by the following formula.
Insert picture description here
The implementation code is as follows:

public class KnapsackProblem {
    
    

    public static void knapsackProblem(int[] weight, int[] value, int capacity) {
    
    

        //记录不同容量不同商品数量的总价值
        //为了方便理解和编写,我们从数组的第一行第一列开始统计
        int[][] totalValue = new int[weight.length + 1][capacity + 1];
        //记录对应位置应该装的商品id
        String[][] goods = new String[weight.length + 1][capacity + 1];

        //初始化:避免null, 与算法无关
        for (int i = 0; i < totalValue.length; i++) {
    
    
            goods[i][0] = "";
        }
        for (int j = 0; j < totalValue[0].length; j++) {
    
    
            goods[0][j] = "";
        }

        for (int i = 1; i < totalValue.length; i++) {
    
    
            for (int j = 1; j < totalValue[i].length; j++) {
    
    
                //判断每个网格放入的内容
                if (weight[i - 1] <= j) {
    
    
                    int temp = value[i - 1] + totalValue[i - 1][j - weight[i - 1]];
                    if (temp > totalValue[i - 1][j]) {
    
    
                        totalValue[i][j] = temp;
                        goods[i][j] = (i - 1) + " " + goods[i - 1][j - weight[i - 1]];
                    } else {
    
    
                        totalValue[i][j] = totalValue[i - 1][j];
                        goods[i][j] = goods[i - 1][j];
                    }

                } else {
    
    
                    totalValue[i][j] = totalValue[i - 1][j];
                    goods[i][j] = goods[i - 1][j];
                }
            }
        }

        System.out.println("应该偷的商品序号:" + goods[weight.length][capacity]);
        System.out.println("商品总价值:" + totalValue[weight.length][capacity]);

    }

    public static void main(String[] args) {
    
    
        int[] weight = new int[]{
    
    1, 4, 3};
        int[] value = new int[]{
    
    1500, 3000, 2000};
        int capacity = 4;
        knapsackProblem(weight, value, capacity);

    }

}

How to judge whether this problem can be solved by dynamic programming?

① When a certain index needs to be optimized under given constraints, dynamic programming can be used.
② The problem can be decomposed into sub-problems, and the solution of the sub-problems can be promoted to solve the problem.

How to use dynamic programming to solve the problem?

① Each dynamic programming solution involves a grid. Each cell in the grid represents a sub-problem of the problem, so the most important thing is how to divide the problem into sub-problems? What is the coordinate axis corresponding to the grid?
② What do I need to add to the value in the cell? The value in the cell is usually the value you want to optimize. For example, in the knapsack problem, the value of the cell is the value of the commodity.

Classic problem 2-the longest common subsequence

Given two strings, find their longest common subsequence. Click here for detailed questions .

We can decompose this problem into solving the longest common subsequence of these two string substrings.
Such as: seeking "fosh"and "fish"longest common subsequence, we can seek first "f"and "f"longest common subsequence, then seek "fo"and "f"longest common subsequence, and so, the next question is the solution of a problem on the basis of Solve again, so the grid is as shown in the figure below: After
Insert picture description here
getting the grid, we try to gradually add data to the grid to derive the calculation formula for each grid. The final grid result is as follows.
Insert picture description here
Analyzing the calculation formula of each grid synchronously when adding data, we can get the following formula.
Insert picture description here
code show as below:

public class LongestCommonSubsequence {
    
    
    public int longestCommonSubsequence(String text1, String text2) {
    
    
        //为了方便计算,网格分别再第一行和第一列前插入空行和空列
        int[][] grid = new int[text1.length() + 1][text2.length() + 1];
        //因此,此处从1开始
        for (int i = 1; i < grid.length; i++) {
    
    
            for (int j = 1; j < grid[i].length; j++) {
    
    
                //此处访问text中的值要减1
                if (text1.charAt(i - 1) == text2.charAt(j - 1)) {
    
    
                    grid[i][j] = grid[i-1][j-1] + 1;
                } else {
    
    
                    grid[i][j] = Math.max(grid[i - 1][j], grid[i][j - 1]);
                }
            }
        }
        //返回最终结果
        return grid[text1.length()][text2.length()];
    }

    //测试代码
    public static void main(String[] args) {
    
    
        System.out.println(new LongestCommonSubsequence().longestCommonSubsequence("fosh", "fish"));
    }
}

Reference: "Algorithm Diagram" Chapter 9 Dynamic Programming

Guess you like

Origin blog.csdn.net/AmorFati1996/article/details/111195130