The learning path of dynamic programming algorithm

The dynamic programming algorithm can be said to be one of the algorithms required for written examinations and interviews of major Internet companies. In order to seize the golden nine silver ten, learning must race against time...

But how to distinguish whether the problem can be solved using dynamic programming ? Don't worry, the characteristics of dynamic programming topics can be roughly divided into the following three categories:

1. count

-How many ways to go to the lower right corner, such as robot wayfinding, etc.

-How many ways are there to select k numbers so that the sum is sum

2. Find the maximum and minimum

-The maximum number sum of the path from the upper left corner to the lower right corner

-Longest ascending subsequence length

3. Seek existence

-Take the stone game, whether the first player will win

-Can we choose k numbers so that the sum is sum

What is dynamic programming?

Next, we will conduct further analysis through sample questions.

Topic: You have three kinds of coins, each with a face value of 2, 5 and 7 yuan. There are enough coins for each. It costs 27 yuan to buy a book. How to use the least coin combination to just pay off without the other party looking for money.

Intuition: Intuitive analysis, use the least coin combination—>Try to use coins with a large face value, then

  • 7+7+7=21
  • 21+5=26
  • emmmmm ....

Looks like it won’t work, come again, change strategy

Improved algorithm: try to use the largest coin, and finally if you can use one coin to pay off

  • 7+7+7=21
  • 21+2+2+2=27
  • 6 coins, right?

But the answer is actually, it is

Correct answer: 7+5+5+5+5=27,5 coins

Hey, according to the algorithm, let's do the questions step by step, not YY.

The first step: the dynamic programming component-determine the state

  • The role of state in dynamic programming belongs to Dinghai Shenzhen
  • In short, when solving dynamic programming, you need to open an array. What does each element f[i] or f[i][j] of the array represent, similar to what X, Y, Z represent in solving math problems
  • Determining the state requires two awareness: the last step; the sub-problem

last step

  • Although we don’t know what the optimal strategy is, the optimal strategy must be k coins a1, a2, a3,..., ak, and the total face value is 27
  • So there must be a final coin: ak
  • Remove this coin, the face value of the previous coins add up to 27-ak

Key point 1

We don’t care how the previous k-1 coin spells 27-ak (there may be 1 spelling, there may be 100 spellings), and we don’t even know ak and k, but we can be sure of the front The coin spelled out 27-ak.

Key point 2

Because it is the optimal strategy, the number of coins to spell out 27-ak must be the least, otherwise this is not the optimal strategy.

Sub-problem

  • So we require: how many coins can be used to spell 27-ak at least
  • The original question is how many coins should be used to make 27 at least
  • We transformed the original problem into a sub-problem, and on a smaller scale: 27-ak
  • In order to simplify the definition, we set the state f(X) = the least number of coins to make X

But wait, we don’t know what the last coin ak is

Since three currency values ​​are given in the question, the last coin ak can only be 2, 5 or 7

  • If ak is 2, f(27) should be f(27-2)+1 (plus the last coin 2)
  • If ak is 5, f(27) should be f(27-5)+1 (plus the last coin 5)
  • If ak is 7, f(27) should be f(27-7)+1 (plus the last coin 7)

Other than that, there is no other possibility

Therefore, the minimum number of coins is required, so it is not difficult to derive the following relationship

f(27)=min{f(27-2)+1,f(27-5)+1,f(27-7)+1}

According to the above derivation, we can easily write a recursive program, as follows

public static void main(String[] args) {
        System.out.println(getMinCoinCount(27));//5
    }

    //写一个方法,获取购买X元书需要的最少硬币
    public static int getMinCoinCount(int X) {
        if (X == 0) return 0;//递归的出口
        int res = Integer.MAX_VALUE;//将初始值设置为最大值

        //如果ak为2
        if (X >= 2 && getMinCoinCount(X - 2) != Integer.MAX_VALUE) {
            res = Math.min(getMinCoinCount(X - 2) + 1, res);
        }

        //如果ak为5
        if (X >= 5 && getMinCoinCount(X - 5) != Integer.MAX_VALUE) {
            res = Math.min(getMinCoinCount(X - 5) + 1, res);
        }

        //如果ak为7
        if (X >= 7 && getMinCoinCount(X - 7) != Integer.MAX_VALUE) {
            res = Math.min(getMinCoinCount(X - 7) + 1, res);
        }
        return res;
    }

Although recursion can solve the problem, it is not the best solution. Let’s talk about the problem of recursive solution.

It is not difficult to see from the figure that f(20) is repeatedly calculated three times and f(15) is repeatedly calculated twice. How to solve this problem? The protagonist's dynamic planning stood up again, "Let go of that equation and let me come". The second step of dynamic planning, on the stage of history

Dynamic programming component two-transfer equation

  • Let state f[X]= how many coins to spell out X at least
  • For any X, f(X)=min{f(X-2)+1,f(X-5)+1,f(X-7)+1}

Now, the transfer equation is there, but it is not over yet, there is still something.

Dynamic programming component three-initial conditions and boundary conditions

  • f (X) = min {f (X-2) + 1, f (X-5) + 1, f (X-7) +1}
  • Two questions: What if X-2, X-5 or X-7 is less than 0? When to stop?
  • If Y cannot be spelled out, define f[Y]=positive infinity, for example: f[-1] = f[-2] = ... = positive infinity
  • So f[1] = min{f[-1]+1,f[-4]+1,f[-6]+1} = positive infinity, which means you cannot spell 1
  • Initial conditions : f[0] = 0

Dynamic programming component four-calculation sequence

  • The minimum number of coins required to spell X: f(X) = min{f(X-2)+1,f(X-5)+1,f(X-7)+1}
  • Initial conditions: f[0] = 0
  • Then calculate f[1],f[2],...,f[27]
  • When we calculate f[X], f[X-2], f[X-5], f[X-7] have all got the result

f[X]=How many coins should be used to make X at least

f[X]=infinity means that X cannot be spelled out with coins

  • Try three coins at each step, a total of 27 steps
  • Compared with recursion, there is no double calculation
  • Algorithm time complexity (that is, the number of steps that need to be performed): 27*3
  • Recursion time complexity: >>27*3

summary

Dynamic programming

The components of dynamic programming:

1. Determine the status

  • The last step (the last coin ak used in the optimal strategy)
  • Transformation sub-problem (the smallest coin spells out a smaller face value 27-ak)

2. Transfer equation

  • f (X) = min {f (X-2) + 1, f (X-5) + 1, f (X-7) +1}

3. Initial conditions and boundary conditions

  • f[0] = 0, if you cannot spell Y, f[Y] = positive infinity

4. Calculation order

  • f[0],f[1],f[2],...

Eliminate redundancy and speed up calculations

Finally the code is implemented, it's over!

public static void main(String[] args) {
        int[] arr = {2, 5, 7};//币值的种类
        int M = 37;//商品总价
        System.out.println(getMinCoinCount(arr, M));
    }

    public static int getMinCoinCount(int[] arr, int M) {
        int[] f = new int[M + 1];//定义动态规划的一维数组
        f[0] = 0;//初始条件
        
        for (int i = 1; i <= M; i++) {
            f[i] = Integer.MAX_VALUE;//初值设置为无穷大
            for (int j = 0; j < arr.length; j++) {
                if (i >= arr[j] && f[i - arr[j]] != Integer.MAX_VALUE) {
                    f[i] = Math.min(f[i - arr[j]] + 1, f[i]);
                }
            }
        }
        
        if (f[M] == Integer.MAX_VALUE) {//如果拼不出,返回-1
            f[M] = -1;
        }
        
        return f[M];
    }

The above content is from the Nine Chapter Algorithm Course at Station B.

Course address https://www.bilibili.com/video/BV1xb411e7ww?from=search&seid=15667342454332890058

Guess you like

Origin blog.csdn.net/weixin_43419256/article/details/107923888