I. Concept of Dynamic Planning
Dynamic Programming solves the entire problem by combining sub-problems. The splitting algorithm divides a problem into several independent subproblems, recursively solves each subproblem, and then merges the subproblems to obtain the solution of the original problem, dynamic Planning is applicable to subproblems that are not independent, that is, each subproblem contains public subproblems. In this case, the adoption of the divide and conquer method will do a lot of unnecessary work, that is, repeated solutions to public subproblems. The dynamic planning algorithm solves each subproblem only once and saves the results in a table, so as to avoid re-calculating the answer every time a subproblem occurs.
Dynamic Planning is usually applied to optimization problems. Such problems may have many feasible solutions. Each solution has a value, and we want to find a solution with the optimal (maximum or minimum) value. This solution is called "One" optimal solution for the problem, rather than "definite" optimal solution, because there may be multiple solutions to obtain the optimal value.
To reduce the time required to repeatedly find the same subproblem, an array is introduced, no matter whether they are useful for the final solution or not, to resolve all subproblems in the array, this is the basic method used for dynamic planning.
II. General steps for Dynamic Planning and solving
The design of the dynamic planning algorithm can be divided into the following four steps:
1> describe the structure of the optimal solution.
2> recursively define the value of the optimal solution.
3> calculate the optimal value based on the bottom-up mode.
4> construct an optimal solution based on the calculated results.
This is the general step of the dynamic planning algorithm. It certainly does not make any sense to say this. Next we will explain how to apply the Dynamic Planning Idea step by solving the longest public subsequence problem.
Iii. Longest Common subsequence Problem Description
Problem description: The subsequence of a character sequence is a character sequence formed by removing a number of characters (either one or not) from a given Character Sequence at Will (not necessarily consecutive. Make the given character sequence X = "x0, X1 ,... xm-1 ", Character Sequence y =" y0, Y1 ,..., yk-1 "is the sub-sequence of X, there is a strict increasing of X (Note: not continuous increasing) subscript sequence <I0, i1 ,..., ik-1>, making for all j = 1 = 0, 1 ,..., k-1 with XJ = YJ. For example, x = "abcbdab" and Y = "bcdb" are subsequences of X.
First, let's ask the question: Assume the string x = "abcbdab", y = "bdcaba", and find their longest common subsequence.
4. Dynamic Planning for solving the longest public subsequence Problem
1> describe the structure of the optimal solution.
A powerful method to solve the above problem is to enumerate all sub-sequences of X, check one by one to see if it is a sub-sequence of Y, and record the largest sequence of Y at any time. Each subsequence of X corresponds to a subset of the subscript set {1, 2,..., m} of X. X has a total of 2 ^ m subsequences. Therefore, this method requires exponential time, which is impractical for long sequences.
Set x = <x1, x2 ,..., XM> and Y = <Y1, Y2 ,..., YN> is two sequences with Z = <Z1, Z2 ,..., ZK> is the longest common subsequence of X and Y. Then we can draw the following conclusions:
1) if XM = YN, then zk = XM = YN, And the zk-1 is a Longest Common subsequence of the Xm-1 and Yn-1.
2) If XM! = YN, so ZK! = XM contains Z, which is the longest common subsequence of Xm-1 and YN.
3) If XM! = YN, so ZK! = YN contains Z, which is the longest common subsequence of XM and Yn-1.
In this way, when looking for the longest common subsequence of X and Y, if there is a Xm-1 = Yn-1, then further solve a subproblem, look for "x0, X1 ,..., xm-2 "and" y0, Y1 ,..., one of the longest common subsequences of yn-2 "; if Xm-1! = Yn-1, you need to solve two sub-problems, find "x0, X1 ,..., xm-2 "and" y0, Y1 ,..., one of the longest common subsequences of yn-1 and find out "x0, X1 ,..., xm-1 "and" y0, Y1 ,..., the longest common subsequence of yn-2, then the elders of the two serve as the longest common subsequence of X and Y.
2> recursively define the value of the Optimal Solution
The recursive solution to the longest common subsequence problem involves creating an optimal recursive formula. Define the sequence of C [I, j] as the length of the longest common subsequence of Xi and YJ. If I = 0 or J = 0, the length of one of the sequences is 0, so the length of the longest common subsequences is 0. The recursive formula is available from the optimal sub-structure of the longest common subsequence problem.
3> calculate the optimal value based on the bottom-up mode
Introduce a two-dimensional array, C [I] [J], and use C [I] [J] to record the length of the longest common subsequence of X [I] AND Y [J, B [I] [J] records C [I] [J] are obtained through the value of that subproblem to determine that we use bottom-up for Recursive calculation in the search, before C [I, j] is calculated, C [I-1] [J-1], C [I-1] [J] and C [I] [J-1] have been calculated. In this case, we can determine whether X [I] = Y [J] Or X [I]. = Y [J] to calculate C [I] [J].
For (INT I = 1; I <= nxlen; I ++) {for (Int J = 1; j <= nylen; j ++) {If (strx [I] = stry [J]) {C [I] [J] = C [I-1] [J-1] + 1; B [I] [J] = 0;} else {//! Note the = here, it indicates, if C [I-1] [J] = C [I] [J-1, it can be left or up //! At this time, the left direction is selected. When the longest public subsequence is output in this way, only one subsequence can be output and needs to be improved !! <Span style = "color: # ff0000;"> If (C [I-1] [J]> = C [I] [J-1]) </span> {C [I] [J] = C [I-1] [J]; B [I] [J] = 1 ;//! Left shift} else {C [I] [J] = C [I] [J-1]; B [I] [J] =-1 ;//! Right Shift }}}}4> construct an optimal solution based on the calculated results.
void PrintAllCase(int B[][MAX_LEN], const string &strX, int i, int j){if (i == 0 || j == 0){return ;}if (B[i][j] == 0){PrintAllCase(B, strX, i-1, j-1);cout << strX[i-1];}else if (B[i][j] == 1){PrintAllCase(B, strX, i-1, j);}else{PrintAllCase(B, strX, i, j-1);}}
V. C ++ implementation code
/*************************************** *********************************** The longest time to solve the Dynamic Planning public subsequences *//********************************** **************************************/# include <stdlib. h >#include <iostream >#include <string> using namespace STD; # define max_len 100 void LCS (const string & strx, const string & stry, int nxlen, int nylen, int C [] [max_len], int B [] [max_len]) {for (INT I = 0; I <= nxlen; I ++ ){ C [I] [0] = 0;} For (Int J = 0; j <= nylen; j ++) {C [0] [J] = 0 ;} for (INT I = 1; I <= nxlen; I ++) {for (Int J = 1; j <= nylen; j ++) {If (strx [I] = stry [J]) {C [I] [J] = C [I-1] [J-1] + 1; B [I] [J] = 0;} else {//! Note the = here, it indicates, if C [I-1] [J] = C [I] [J-1, it can be left or up //! At this time, the left direction is selected. When the longest public subsequence is output in this way, only one subsequence can be output and needs to be improved !! If (C [I-1] [J]> = C [I] [J-1]) {C [I] [J] = C [I-1] [J]; B [I] [J] = 1 ;//! Left shift} else {C [I] [J] = C [I] [J-1]; B [I] [J] =-1 ;//! Right Shift }}} void printallcase (int B [] [max_len], const string & strx, int I, Int J) {if (I = 0 | j = 0) {return;} If (B [I] [J] = 0) {printallcase (B, strx, I-1, j-1); cout <strx [I-1];} else if (B [I] [J] = 1) {printallcase (B, strx, I-1, J );} else {printallcase (B, strx, I, J-1) ;}} int main () {string strx = "abcbdab"; string stry = "bdcaba "; int C [max_len] [max_len]; //! The length of the longest common subsequence is recorded. Int B [max_len] [max_len]; //! Int nxlen = strx. length (); int nylen = stry. length (); LCS (strx, stry, nxlen, nylen, C, B ); cout <"the max length of LCS is" <C [nxlen] [nylen] <Endl; cout <"the LCS are:"; printallcase (B, strx, nxlen, nylen); System ("pause"); Return 0 ;}Note: The key here is to understand the applicability of the two-dimensional arrays C and B, and why to use them.
The current algorithm can output only one output when outputting the longest common subsequence. If you need to output all the results, you need to improve the algorithm.
[Introduction to algorithms 7] The Longest Common subsequence for Dynamic Programming