[Algorithm notes] Dynamic programming DP, description of the algorithm

[Algorithm notes] Dynamic programming DP

Dynamic Programming

I believe that everyone uses recursion extensively in the implementation of the code, but pure recursion, although the implementation is very simple, but we know that in the algorithm, most of the time cannot have both. Recursion is a function call to itself, and it is necessary at this time In terms of time and space, every function call will be allocated in the memory stack to save temporary variables, save parameters and return addresses. Moreover, recursion often has repeated calculation steps. Finally, too many calls can easily overflow.

Dynamic programming greatly solves the problem of repeated calls. It is significantly different from the divide and conquer strategy (Divide and Conquer) in that the sub-problems of dynamic programming are not completely overlapping. In fact, dynamic programming and traversal algorithms are very similar. There is nothing superb in the idea of ​​??, but for the saved calculations that have been done, the results can be quickly calculated when repeated calls, saving time. It is worth mentioning that all problems that can be solved using greedy algorithms can be solved by dynamic programming. Many specific algorithms have the shadow of dynamic programming, such as the shortest path Floyd-Warshall algorithm (Floyd-Warshall algorithm)

Definition:

An algorithm that defines the relationship between the state of the problem and the state by splitting the problem, so that the problem can be solved in a recursive (or divide and conquer) manner [1]

Of course, this definition is not optimal. We call the recurring sub-problems overlapping sub-problems (overlapping sub-problem). Then its definition can be: split a problem into several overlapping sub-problems, and then combine the solutions of the small problems to get the solution of the big problem.

Dynamic programming is widely used in fields of computing science (AI, graphics etc), information theory, cybernetics, etc.

Step

Dynamic programming methods are usually used to solve optimization problems. This type of problem can have many feasible solutions, and each solution has a value. We hope to find the solution with the optimal value (maximum or optimal value). We call such a solution the optimal solution of the problem (an
optimal solution), not the optimal solution (the optimal solution), because there may be multiple solutions that reach the optimal value [2. Thomas H. Cormen, Charles E. Leiserson ,Ronald L. Rivest and Clifford Stein, 2019.6, China Machine Press, 204]

1. Characterize the structural characteristics of an optimal solution
2. Recursively define the value
of the optimal solution 3. Calculate the value of the optimal solution
4. Use the calculated information to construct an optimal solution The
first three steps are the basis for dynamic programming to solve the problem , If we only need the value of the optimal solution instead of the solution itself, then we can ignore the fourth step

Example

1. Fibonacci sequence
Observe the following code

double F(int n){
	return (n<=1)?1:F(n-1)+F(n-2)
}

The run-time is shown in

Figure 1

Calculate T(n)=O(2^n)
If we need to calculate F(44) , we need to calculate F(43) and F(42) , and to calculate F(43) , we need to calculate F(42) , when When the number in the function becomes smaller, the situation becomes more uncontrollable.
Insert picture description here
Figure 2

Of course we don’t need to calculate *F(10)* almost ten million times, so we need to solve this problem.
There is such a feasible strategy:
·In order to avoid double calculation, store the amount of intermediate calculation in the table (memorization)
·We remember The values ​​of these calculations are the next possible repeated calls.
In the process of dynamic programming to solve the optimal problem, the top-down solution may need to repeatedly obtain the optimal solution for the same sub-problem. This is also where it is significantly different from the divide-and-conquer algorithm, because the sub-problems of the divide-and-conquer algorithm are completely different, so the effect is better.

#define MAX 100
int d[MAX]
int F(int n){
    
    
	if(n<=2)
	{
    
    
		return 1;
	}
	else
	{
    
    
		d[n-1]=F(n-1);
		d[n-2]=F(n-2);
		d[n]=d[n-1]+d[n-2];
		return d[n]
	}
}
//也可以用循环的方式
}

2. Interval scheduling
·Course j starts at s[j] and ends at f[j], and the degree of importance is w[j]>0;
·When two courses do not overlap, these two courses are called It is compatible.
Goal: Find a set of compatible courses with the greatest weight.
Insert picture description here
Figure 3

We go from the shallower to the deeper, and the most brute-force method (brute-force) is of course to take out all the arrangement of each course and see which weight is the largest. However, this obviously has a lot of room for improvement. For example, there must be many overlaps in the arrangement of these courses. So what to do?
When the weights are all 1, you can use the greedy algorithm to sort directly according to the end time and start from the back. However, different weights are added here, so the more courses included, it does not necessarily mean that the final weight and the maximum are obtained. At
this time, DP comes in handy. The idea is similar to the above method, but an array p needs to be added. Assist

p[j]=the largest course compatible with course j that is smaller than j
. In the figure below, p[2]=0,p[7]=3
Insert picture description here
Figure 4

We present it more completely
Def. OPT(j)=any compatible subset of courses with the largest weight sum, containing only courses 1, 2, …, j
Goal. OPT(n)=with the largest weight sum The mutually compatible course set
Case 1.OPT(j) does not contain the course j
. So its solution is to only contain the maximum weight of courses 1, 2,...,j and are compatible with each other.

Case 2. OPT(j) contains course j
· Add weight w[j]
· Does not contain incompatible courses {p[j]+1,…,j-1}
· Must contain 1, 2, ..., p( j) Optimal solution

After the above analysis, is it very clear? The Bellman formula for dynamic programming has also come out
Insert picture description here
Figure 5

Let's analyze the algorithm complexity (complexity).
Note that in each iteration, the worst is OPT(j-1), so in the dynamic programming process, it runs at most 2n times, which is O(n), and p[j] Acquisition is obtained by sorting the provided course intervals according to the end time and counting from back to front. The total complexity is O(nlogn), and the total algorithm complexity is O(nlogn).

3. Multi-point curve fitting
Let me give another example that I think is more interesting. I believe that everyone will use curve fitting when doing data processing, which makes us a part of the research process, but when the points appearing are arranged in different When the interval changes greatly, there is no way to fit a curve. Below we use dynamic programming to solve this problem.
First look at the most basic problem:

Least squares
n points (x1, y1), (x2, y2),..., (xn, yn) in a given plane. Find a line y=ax+b to fit.
The most common problem is to use the least squares method.
Insert picture description here
Figure 6
!](https://img-blog.csdnimg.cn/20210110134349420.png)

Figure 7

Segmented Least squares
· Given n points (x1,y1),…,(xn,yn), x1<x2<…<xn, find a set of curves to minimize the error of f(x)
Insert picture description here
Figure 8
f(x)= E+cL
E: the sum of the square errors of each straight line
L: the number of straight lines
OPT(j) = the minimum consumption for points p1,...,pj
eij=pi,...,pj's SSE
then each time Cost=eij+ c+OPT(i-1)
finally get Bellman's equation
Insert picture description here
Figure 9

Sample

All algorithms need the following three components: main idea, proof of correctness, and run time analysis

1. The main idea of ​​the algorithm. You should correctly convey the idea of ​​the algorithm in this section. It does not need to provide all the details of the solution or the correct reason. For example, in a dynamic programming problem, you should tell us the sub-problems, basic conditions and recursive formulas in this part. You can also use pseudo code to make it look clearer

2. Proof of the correctness of the algorithm. No matter what the input is, you must prove that your algorithm is correct. For loops and iterative algorithms, the usual method is to look for invariants. A loop invariant needs to follow the following three principles:
1) It is right before the first iteration and the loop
2) If it is right before the i-th iteration, then it must also be right before the i+1th time Yes
3) If it is
correct after the last iteration or loop, then your output is correct as a proof. This invariant needs to be described carefully by the system. If the correctness is proved to be correct in the class, Then you don’t have to prove its correctness every time

3. Complexity analysis, usually time complexity analysis, marked with O(·). And prove why this complexity

Having said so much, let’s give you an example. This example comes from my homework.
Given a set of non-negative integers of length N and a value W, judge whether there is a subset in this set of numbers, so that the sum of the subsets is equal to W ?
1. Core idea: Let S denote this set of input non-negative integers, we build a Boolean type two-dimensional array dp[][] to realize dynamic programming, dp[i][j] indicates whether there is i before including S The subset of elements and the subset sum is j, we want to know dp[N-1][W]. We initialize first, when j=0, dp[i][j]=true, the Bellman formula is
Insert picture description here
Figure 10

2. Correctness
Obviously, since the empty set is a subset of all sets, when j=0, dp[i][j]=true. For dp[i][j], if the i-th element is greater than j, then this subset does not exist in the final answer, dp[i][j]=dp[i-1][j]. Otherwise, there are two cases. If the answer does not contain the i-th element, then dp[i][j]=dp[i-1][j]. If the answer contains the i-th element, then the subset and reduce, dp[i][j]=dp[i-1][jS[i]]. It is correct to satisfy any of the above two conditions d[i][j]

3. Complexity analysis
Because there are two layers of loops, one of which is the length of the set, and the other is the value W, so the complexity is θ(NW)

Oh, I’m tired of translating my homework, let’s show everyone my answer.
Insert picture description here
Figure 11

to sum up

In general, the idea of ​​dynamic programming is very simple, that is, save the previously calculated values, thereby saving time for repeated calculations. Divided into three steps, define the sub-questions, divide the main question into sub-questions, and determine the order of small to large sub-questions that can make the answer to the small sub-question constitute the answer to the larger sub-question. The analysis method is also very simple, such as choosing one of the two, choosing one more, and adding the new parameter blablabla (It took me almost six hours to write a blog that I am quite satisfied with. I would really not imagine it if it were not for a holiday)

Guess you like

Origin blog.csdn.net/Cplus_ruler/article/details/112414247