To elicit the basic idea of dynamic programming, consider the following example:
Title Description:
Fibonacci sequence is a common mathematical sequence, also known as the rabbit sequence, it satisfies: a[1]=1,a[2]=1,a[n]=a[n-1]+a[n-2] (n>2), input n, output A[N] mod 10000007 value. (n<=100000).
Input Sample:
3
4
5
Sample output:
2
3
5
"Algorithmic Analysis"
After seeing the topic, we can easily write two versions of the code, one is the recursive code, and the other is the recursive code. Where the recursive code is as follows:
/*prob:fib-recursive author:aqxlang:c++*/#include <iostream> #define MoD 10000007using namespace std;int f (int x) {if (x <=2) return 1;elsereturn (f (x-1) +f (x-2))%mod;} int main () {int N;while (cin>>n) {cout<<f (n) <<endl;}}
This piece of code doesn't seem to be a problem, but it's very slow to run, and when N=100 is unable to get results in a limited amount of time, consider the example of n=5:
When n=5, using recursive thinking calculation, F (3) is repeated call 2 times, F (2) is repeated calls 3 times, and F (i) no matter how many times, its return value is the same,
Therefore, a lot of useless computations were carried out. If you can record the results of F (i) at the first calculation of F (i), the next time the call is made, the value of f (i) will be returned, so that many redundant computations can be avoided. In this way, the redundancy calculation is omitted, the efficiency of the program has been improved quality.
"Program Implementation"
/*prob:fib-memory author:aqxlang:c++*/#include <iostream> #define MoD 10000007using namespace Std;int a[100001];int f (int x) {if (a[x]!=0) return a[x];if (x<=2) return A[x]=1;elsereturn a[x]= (f (x-1) +f (x-2))%mod;} int main () {int N;while (cin>>n) {cout<<f (n) <<endl;}}
The method of Fibonacci sequence, in the strict sense, may not be considered as dynamic programming, but it is inextricably linked with dynamic programming:
1. The redundant space is used to record the result of the repeated state, and the calculation of redundancy is avoided.
2. Stateful transfer equation (here is f[i]=f[i-1]+f[i-2],i>=3)
3. Any state is directly related to the first few items identified
Some of the commonly used nouns in dynamic programming are explained in the following simple terms:
State: A state is used to describe a definite natural condition or an objective condition, such as in the Fibonacci sequence, where each a[i] is a definite state.
Stage: The process of solving the problem is properly divided into several interconnected stages, so that the process can be solved, and the number of stages may be different. Variables describing the stage are called stage variables. For example, in the Fibonacci sequence, 5 and 4 are a phase, and 5 and 3 are also stages.
No effect: Given a state, the result of this state is affected only by the state of its previous stage, not by its first 2, 3 ... The impact of a phase state. For example, in the Fibonacci sequence, the value of a[5] is affected only by a[4] and a[3], and not by other a[i].
Decision: A decision describes an action or selection that moves from one state to another. For example, A[5]=a[4]+a[3], this is a process of action.
State transitions: State transitions and decisions are very similar, and it is the relationship between two states that is described in the process of decision making. For example, in the Fibonacci sequence, A[i]=a[i-1]+a[i-2] (i>2), this is a state transition equation.
Here is an example:
Demon Password (vijos-p1028)
Title Description:
The son of the wind just went into his examination room, just ...
Flower: When when I am the charm Empress-Flower!! ^^ (gorgeous appearance, salute, flowers)
Son of the Wind: I vomit ... (The eyes that kill people) talk about the topic quickly! otherwise ...-_-###
Flower:...... Ah ~ ~ ~ Cold ~ ~ We are now to solve the Magic clan's password problem (narcissism: There will be some people in the Magic clan password to me and the food worms write love letters, OH alive, of course, to my comparison Dora * ^_^ *). The Demon family now uses a new cipher system. Each password is a given list of English words containing only lowercase letters, each word containing at least 1 letters and a maximum of 75 letters. If in a table consisting of one word or multiple words, except the last one, each word is contained in a subsequent word, that is, the previous word is the prefix of the latter word, then the word list is a chain of words. For example, the following words make up a word chain:
I
Int
Integer
But the following words do not form a word chain:
Integer
Intern
Now all you have to do is take some words out of a given word list and make up the longest word chain, which is the word chain that contains the most words. By counting the number of words, you get the password.
The son of the Wind: the password is the longest word chain includes the number of words ah ...
Flower: Alive, and, the format of these files is, the first behavior word number of words in the table N (1<=n<=2000), each line below a word, in the order of the dictionary, there is no duplicate words in the middle!! The file you want to submit as long as the first line output password on the line ^ ^ See you look good, give you a sample:
Input Sample:
5
I
Int
Integer
Intern
Internet
Sample output:
4
Sample explanation:
I->int->intern->internet
Algorithm Analysis "
This topic is a typical linear dynamic programming, in order to better understand it, we first look at its search implementation. If you use the search algorithm to write this problem, it is very easy to write, the code is as follows:
/*prob:vijos-p1028-dfsauthor:aqxlang:c++*/#include <iostream> #include <string.h>using namespace std; int n;string s[2005];int dp[2005];int ans=0;bool can (int i,int j) {if (i==0) return true;if (S[j].find (s[i]) ==0) return Tru E;return false;} I refers to which string is currently searched,//step refers to the current total number of strings int dfs (int i,int step) {Ans=max (ans,step); for (int j=i+1;j<=n;j++) if (Can ( i,j)) {DFS (j,step+1);} return 0;} int main () {while (cin>>n) {Ans=0;memset (dp,0,sizeof (DP)), for (int i=1;i<=n;i++) {cin>>s[i];} DFS (0,0); Cout<<ans<<endl;}}
But this code can only get 90 points in the hand. (It is very rare to get 90 points in this data scale, and in real-world competitions, such algorithms can only get 50 points or less) so there is a certain amount of content that can be optimized.
Look at an example like this:
Input Yes: i,it,in,int,inter,internet
Also the inter end of the word sequence, the search process will encounter the following several possible:
I->inter
In->inter
Int->inter
I->in->inter
I->int->inter
In->int->inter
I->in->int->inter
They are all word sequences ending in Inter, and then the longest sequence length that can be received is the same, assuming that the longest word sequence length from Inter is X, and the word length of each case received inter end is a[i], then the length of the word sequence in each case is a[i] +x. For the subject, we only focus on the optimal solution, and for all the word sequence ending with Inter, X is the same, then, only the largest a[i] is likely to produce the optimal solution! Other states are useless, we should not calculate it!
Therefore, you can define a state like this:
Dp[i] represents the longest length of a sequence of words ending with the first word. For example, Dp[5] represents the length of the longest sequence in a sequence of words ending in inter. Apparently, dp[5]=4.
After that, let's consider the connection between any two states:
For a dp[i], which dp[j] is associated with it? Take Inter to give an example, a sequence of words ending with Inter, only related to the sequence of words ending with i,in,int. A more general description is: Each J that relates to I satisfies:
1.j<i
2.S[J] is the prefix of s[i]
When J can be connected to the front of I, Dp[j] and dp[i], please see the chart below:
I |
1 |
2 |
3 |
4 |
5 |
6 |
Dp[i] |
1 |
1 |
2 |
3 |
4 |
5 |
For Dp[5], which is associated with dp[1],dp[3],dp[4], that is, a sequence of words ending with a 5th string, which can be followed by a sequence of words ending with 1th, 3, and 4 strings, to form a longer sequence of words, so:
dp[5]=dp[i]+1....................................i=1,3,4
More common:
Dp[i]=dp[j]+1....................................j<i and S[j] is the prefix of s[i]
And we only care about one of the biggest, so we need to make a slight change to this equation:
Dp[i]=max (dp[i],dp[j]+1) ... j<i and s[j] is the prefix of S[i], which is .... .....????
You also need to be aware of the initial state:
Dp[i]=1
Because each string is itself a sequence of words.
With the initial state, state and state transition equations, this is a complete dynamic programming model.
The common implementation methods of dynamic programming are recursive and recursive, so it is easier and more efficient to use recursion to realize it.
Recursion is divided into push and reverse, the subject will be used in two ways to achieve a better understanding of the dynamic planning of the reader
/*prob:vijos-p1028-reverse author:aqxlang:c++*/#include <iostream> #include <string.h>using namespace Std;int N;string s[2005];int Dp[2005];bool can (int i,int j) {if (S[j].find (S[i]) ==0) return True;return false; int main () {while (cin>>n) {memset (dp,0,sizeof (DP)), for (int i=1;i<=n;i++) {cin>>s[i];} int ans=0;//to any one I, enumerates all strings that can be followed before it jfor (int i=1;i<=n;i++) {dp[i]=1;for (int j=1;j<i;j++) if (Can (J,i)) {Dp[i]=max (dp[i],dp[j]+1);} Ans=max (Ans,dp[i]);} Cout<<ans<<endl;}}
/*prob:vijos-p1028-Shun author:aqxlang:c++*/#include <iostream> #include <string.h>using namespace Std;int N;string s[2005];int Dp[2005];bool can (int i,int j) {if (S[j].find (S[i]) ==0) return True;return false; int main () {while (cin>>n) {memset (dp,0,sizeof (DP)), for (int i=1;i<=n;i++) {cin>>s[i];} int ans=0;//to any one I, enumerates which strings it can be connected to before for (int i=1;i<=n;i++) {if (dp[i]==0) dp[i]=1;for (int j=i+1;j<=n;j++) if (Can (I, j)) {Dp[j]=max (dp[j],dp[i]+1);} Ans=max (Ans,dp[i]);} Cout<<ans<<endl;}}
two implementations are slightly different and the time complexity is O (N 2 )
This problem is essentially a kind of very typical linear dynamic programming algorithm: the longest ascending subsequence. The model of the longest ascending subsequence is: A number of sequence bi, when B1 < B2 < ... < BS, we call this sequence ascending. For a given sequence (A1, A2, ..., an), we can get some ascending sub-sequences (AI1, AI2, ..., AiK), here 1 <= i1 < I2 < ... < IK <= N. For example, for sequences (1, 7, 3, 5, 9, 4, 8), there are some ascending sub-sequences of it, such as (1, 7), (3, 4, 8) and so on. The longest length of these subsequence sequences is 4, such as subsequence (1, 3, 5, 8). Your task is to find the length of the longest ascending subsequence for a given sequence.
In fact, the longest ascending subsequence has a better solution, which is not covered here.
Getting started with easy-to-understand dynamic planning