Dynamic programming problem dp problem and classic problem

Dynamic programming

In fact, his thoughts are very similar to divide and conquer. They are divided into sub-problems to find the optimal solution and finally merged to produce the overall optimal solution. But the difference is that if many of the decomposed sub-problems are the same, the same sub-problem using the divide-and-conquer method will be solved multiple times, does it affect the efficiency very much; as for the dynamic programming method, it saves the answers to the solved sub-problems If you have the same sub-question, just use the saved answer directly, saving a lot of calculation time.

Image Source
Insert picture description here

Both dynamic programming and divide-and-conquer divide big problems into small problems. The independence between small problems is divide and conquer, and there is a state relationship between small problems, and the previous state is dynamic programming that needs to be used, and the greedy method is not needed.

The classic problems are finding coins and climbing stairs

(1) Coin change:

Given several kinds of coins of different denominations (the number of coins for each type is unlimited), how to combine several kinds of coins into a certain denomination of money to minimize the number of coins?
In real life, we often use a greedy algorithm. For example, we need 13 yuan to find change. We first find 10 yuan, then 2 yuan, and then 1 yuan. If our change is available, 1, 2, 5, 9, 10 are available. When we change 18 yuan, the greedy algorithm strategy is: 10+5+2+1, four, but obviously you can use two 9 yuan. This kind of problem is generally solved by dynamic programming.

This is the code of a big guy, dfs+pruning

class Solution {
    
    
    public int coinChange(int[] coins, int amount) {
    
    
        Arrays.sort(coins);
        recursion(coins, amount, 0, coins.length - 1);
        return minCount == Integer.MAX_VALUE ? -1 : minCount;
    }
    int minCount = Integer.MAX_VALUE;
    /**
     * 1、按金额从大到小,从多到少(排序,用余数一步到位)
     * 2、预判低于最优解,终止递归(可以返回最优解,不过提升有限,意义不大)
     * 3、能整除即可返回
     */
    void recursion(int[] coins, int amount, int count, int index) {
    
    
        if (index < 0 || count + amount / coins[index] >= minCount) return;
        if (amount % coins[index] == 0) {
    
    
            minCount = Math.min(minCount, count + amount / coins[index]);
            return;
        }
        for (int i = amount / coins[index]; i >= 0; i--) {
    
    
            recursion(coins, amount - i * coins[index], count + i, index - 1);
        }
    }
}

(2) Climbing stairs:

There is a continuous staircase with n steps in total. Climb up from the bottom of the stairs to the top of the stairs. She can step up one step at a time or two steps at a time (but she will never retreat downwards). Ask her how many different ways to climb stairs are there?

To be honest, this kind of thinking is really the same as how many selection methods there are to choose m individuals from n individuals in high school. Assuming that the problem can be decomposed into m individuals, there must be a squad leader + m individuals do not have a squad leader. Then you can recurse and then divide.
Take the last choice of the above stairs as an example, he can go up one step at a time on the n-1th step or two steps at a time on the n-2th step. The sum of the two possibilities is the total possibility. , So the problem can be transformed into T(n)=T(n-1)+T(n-2) , which can be pushed forward recursively. The formula is the same as Fibonacci’s law.

Doing this problem without recursion has a time complexity of O(n) and a space complexity of O(1).

//删去#那些库了,你们可以自己加上
int main()
{
    
    
	int a1, a2;
	int n = 10;
	a1 = 1; 
	a2 = 1;
	for (int i = 1; i < n; i++)
	{
    
    
		int temp = a2;
		a2 = a1 + a2;
		a1 = temp;
	}
	cout << a2;
}

Guess you like

Origin blog.csdn.net/qq_43978754/article/details/115056571