South Mail algorithm analysis and Design Experiment 2 dynamic programming method

Source: Internet
Author: User

Dynamic Programming method

Experimental Purpose:

Deepen the understanding of the algorithm principle and realization process of the dynamic programming method, and learn to solve the problem of the longest common sub-sequence in practical application by dynamic programming method.

Experimental content:

Using the dynamic programming method to find the longest common subsequence of two sequences, the comparison results can be used in many fields such as gene comparison and article comparison.

Experimental Requirements:

Master the idea of dynamic programming method, and the application of dynamic programming method in practice; Analyze the problem characteristics of the longest common subsequence, select the algorithm strategy and design the specific algorithm, programming to achieve the comparison of two input sequences, and output their longest common sub-sequence.


Experimental principles and contents (including operation process, result analysis, etc.)

1. The longest common subsequence (LCS) problem is: Given a two-character sequence x={x1,x2,......, XM} and Z={z1,z2,......, ZK}, it is required to find the longest common subsequence of x and Y.

For example: X={a,b,c,b,d,a,b},z={b,d,c,a,b,a}. Their longest common subsequence, lsc={b,c,d,a}.

Lists all the sub-sequences of all x by "exhaustive", checks if it is a subsequence of Z and records the longest common subsequence and records the length of the longest common subsequence. The solution time is exponential and therefore not available.

2, analysis of the characteristics of the LCS problem, set x={x1,x2,......, xm} and Y={y1,y2,......, yn} for two sequences, z={z1,z2,......, ZK} for their longest common sub-sequence, they must have the following properties:

(1) If Xm=yn, then Zk=xm=yn, and Zk-1 is the longest common subsequence of Xm-1 and Yn-1;

(2) If Xm≠yn and Xm≠zk, then Z is the longest common subsequence of Xm-1 and y;

(3) If Xm≠yn and Zk≠yn, then Z is the longest common sub-sequence of x and Y.

This will solve the problem of the longest common subsequence of x and Y, which can be decomposed into the problem of smaller size:

If Xm=ym, it is further decomposed to solve the problem of the longest common subsequence of the two (prefix) sub-character sequences Xm-1 and Yn-1;

If Xm≠yn, the original problem is converted to solve two sub-problems, that is, to find the longest common subsequence of Xm-1 and Y and to find the longest common subsequence of x and Yn-1, whichever is the longest common sub-sequence of x and Y.

Thus, the longest common subsequence of the two sequences contains the longest common subsequence of the prefixes of the two sequences, with the best substructure properties.

3. C[i][j] Saves the length of the longest common subsequence of the character sequence xi={x1,x2,......, XI} and Yj={y1,y2,......, YJ}, which can be recursive as follows:
0 i=0 or J=0

c[i][j]= c[i-1][j-1]+1 i,j>0 and Xi=yj

MAX{C[I][J-1],C[I-1][J]} i,j>0 and Xi≠yj

Thus, the solution of the longest common subsequence has overlapping sub-problem properties, if the recursive algorithm is implemented, an exponential time algorithm is obtained, so the dynamic programming method is used to solve the problem from the bottom up, which avoids the iterative calculation of sub-problems and completes the calculation in polynomial time.

4, in order to be able to further obtain the optimal solution by the optimal solution (that is, the longest common sub-sequence), also need a two-dimensional array s[][], the element in the array s[i][j] record C[i][j] value is three sub-problem c[i-1][j-1]+1,c[i][j-1] and C[i-1][j] Which computes the current solution component of the optimal solution (that is, the current character in the longest common subsequence) and eventually constructs the longest common subsequence itself.


Code:

#include <iostream> #include <string>using namespace std;int const MaxLen = 50;class Lcs{public:lcs (int nx,        int NY, Char *x, char *y) {m = NX;        n = NY;        A = new Char[m + 2];        b = new Char[n + 2];        memset (A, 0, sizeof (a));        memset (b, 0, sizeof (b));        for (int i = 0; I < NX + 2; i++) A[i + 1] = X[i];        for (int i = 0; i < NY + 2; i++) B[i + 1] = Y[i];        c = new Int[maxlen][maxlen];        s = new Int[maxlen][maxlen];        memset (c, 0, sizeof (c));  memset (s, 0, sizeof (s));  } int lcslength ();  void CLCS () {CLCS (M, n);    }private:void CLCS (int i, int j);    int (*c) [MaxLen], (*s) [MaxLen];    int m, n; Char *a, *b;};    int Lcs::lcslength () {for (int i = 1; I <= m; i++) c[i][0] = 0;    for (int j = 1; J <= N; j + +) C[0][j] = 0;            for (int i = 1, i <= m; i++) {for (int j = 1; J <= N; j + +) {if (a[i] = = B[j])     {           C[I][J] = c[i-1][j-1] + 1;            S[I][J] = 1;                } else if (C[i-1][j] >= c[i][j-1]) {c[i][j] = c[i-1][j];            S[I][J] = 2;                } else {c[i][j] = c[i][j-1];            S[I][J] = 3;  }}} return c[m][n];    }void Lcs::clcs (int i, int j) {if (i = = 0 | | j = 0) return;        if (s[i][j] = = 1) {CLCS (i-1, j-1);    cout << A[i];    } else if (s[i][j] = = 2) CLCS (I-1, J); else CLCS (i, j-1);}    int main () {int NX, NY;    Char *x = new Char[maxlen], *y = new Char[maxlen];    cout << "Please enter x (without spaces)" << Endl;    scanf ("%s", x);    NX = strlen (x);    cout << "Please enter Y (without spaces)" << Endl;    scanf ("%s", y);    NY = strlen (y);    LCS LCS (NX, NY, X, y); cout << "The length of the longest common subsequence of x and Y is:" << LCS.    Lcslength () << Endl;    cout << "The sequence is" << Endl; Lcs.CLCS ();    cout << Endl;    delete []x;    delete []y; return 0;}

Analysis of Complexity:

The average time complexity of int lcslength () is O ();

The average time complexity of void CLCS () is O (Nlogn).


Study Questions

1, Memo method is a variant of dynamic programming method, it uses the idea of split-treatment method, the top-down direct recursion to find the optimal solution. However, unlike the divide-and-conquer approach, the memo method establishes a memo for each of the computed sub-problems, which is to save the calculation results of the sub-problems for use when needed, thus avoiding the problem of sub-problems.

Try overwriting the current intlcslength () function and use the memo method to solve the longest common sub-sequence. (Hint: The memo method takes a recursive solution, so a public member function intlcslength () is required to invoke the private recursive member function int lcslength (int i,int j);

int lcs::lcslength (int i, int j) {    if (i = = 0 | | j = = 0)         return 0;    if (c[i][j]! = 0)         return c[i][j];    else    {        if (a[i] = = B[j])        {            c[i][j] + lcslength (i-1, j-1) + 1;            S[I][J] = 1;        }        else if (Lcslength (I-1, J) >= Lcslength (i, j-1))        {            C[i][j] = Lcslength (I-1, j);            S[I][J] = 2;        }        else        {          C[i][j] = lcslength (i, j-1);          S[I][J] = 3;        }    }    return c[i][j];}

2. If we omit the two-dimensional array s in the original program, can we find the optimal solution of the longest common sub-sequence problem? Write a similar CLCS algorithm implementation: the ability to construct the longest common subsequence within the time of O (m+n) without the help of a two-dimensional array s. (Hint: At this point you can compare a[i] and B[j] at the current c[i][j]. If equal, call CLCS (i-1,j-1), output A[I] (or b[j]). If not equal, compare c[i-1][j] and c[i][j-1]. If C[I-1][J]≥C[I][J-1], the CLCS (I-1,J) is called recursively; otherwise, CLCS (I,J-1) is called recursively. )

void Lcs::clcs (int i, int j) {    if (i = = 0 | | j = = 0)         return;    if (a[i] = = B[j])    {        CLCS (i-1, j-1);        cout << a[i];    }    else    {        if (C[i-1][j] >= c[i][j-1])             CLCS (I-1, j);        else             CLCS (i, j-1);    

3, if we only need to calculate the length of the longest common sub-sequence, without constructing the optimal solution, how to improve the original program can make the space requirements of the algorithm greatly reduced? Please rewrite the original program to reduce the space complexity of the algorithm to O (Min{m,n}). (Tip: Calculation C[i][j] uses only the line I and i-1 elements, so the length of the longest common subsequence can be computed with only two rows of element space, and a shorter sequence length is used as the Y sequence to shorten the number of elements per row, further reducing space complexity. )

#include <iostream> #include <string> #include <algorithm>using namespace std; #define MAX 50class lcs{        Public:lcs (int nx, int ny, Char *x, char *y) {m = NX;        n = NY;        A = new Char[m + 1];        b = new Char[n + 1];        memset (A, 0, sizeof (a));        memset (b, 0, sizeof (b));        for (int i = 0; i < NX; i++) A[i + 1] = X[i];        for (int i = 0; i < NY; i++) B[i + 1] = Y[i];            if (M > N) {l = m;        s = n;            } else {char *t;            Swap (x, y);            s = m;        L = N;        } C1 = new Int[s + 1];        C2 = new Int[s + 1];        memset (c1, 0, sizeof (C1));    memset (c2, 0, sizeof (C2));    } int lcslength ();p rivate:int m, N;    int *C1, *C2;    int L, S; Char *a, *b;};    int Lcs::lcslength () {for (int i = 0; i < s; i++) c1[i] = 0; for (int i = 1, i <= l; i++) {for (int j = 1; J <= S; J + +) {if (a[i] = = B[j]) c2[j] = c1[j-1] + 1;            else if (C1[j] >= c2[j-1]) c2[j] = C1[j];        else c2[j] = c2[j-1];    } for (int j = 0; J < S; j + +) C1[j] = C2[j]; } return c2[s];}    int main () {int NX, NY;    Char *x, *y;    x = new Char[max];    y = new Char[max];    cout << "Please enter x (without spaces)" << Endl;    CIN >> X;    NX = strlen (x);    cout << "Please enter Y (without spaces)" << Endl;    Cin >> y;    NY = strlen (y);    LCS LCS (NX, NY, X, y); cout << "The length of the longest common subsequence of x and Y is:" << LCS.    Lcslength () << Endl;    delete []x;    delete []y; return 0;}

4. Consider: How can I modify the LCS algorithm if it is required to output all the longest common subsequence sequences possible?

Original CLCS function if (c[i-1][j]>=c[i][j-1]) ... The statement does not distinguish between c[i-1][j]>c[i][j-1] and C[i-1][j]=c[i][j-1] in two different cases. So to find all LCS, it must be in a[i]!=b[j] and c[i-1][j]==c[i][j-1], respectively, along the c[i-1][j] up and c[i][j-1] to the left two search direction to construct the optimal solution, in order to find all the LCS accordingly. An solution[] array can be used to record the optimal solution vector when implemented. )



Example of dynamic programming method: Bracketssequence

Description

Letus define a regular brackets sequence in the following by:

1. Empty sequence is a regular sequence.
2. If S is a regular sequence, then (s) and [s] are both regular sequences.
3. If A and B are regular sequences, then AB is A regular sequence.

For example, all of the following sequences of characters is regular bracketssequences:

(), [], (()), ([]), ()[], ()[()]

And all of the following character sequences is not:

(, [, ), ) (, ([)], ([(]

Some sequence of characters ' (', ') ', ' [', and '] ' is given. Findthe shortest possible regular brackets sequence, that contains the givencharacter sequence as a subsequence . Here, a string A1 A2 ... is called Asubsequence of the string B1 b2 ... bm, if there exist such indices 1 = i1 <i2 & Lt ... < in = m, which AJ = bij for all 1 = j = N.

Input

Theinput file contains at most of brackets (characters ' (', ') ', ' [' and '] ') that is situated on a single line without a NY other characters among them.

Output

WriteTo the output file a single line this contains some regular brackets sequencethat has the minimal possible length and Contains the given sequence as asubsequence.

Sample Input

([(]

Sample Output

()[()]


The main idea: to give some parentheses, to ask them to legally at least how many parentheses to add, and output the result after the addition, the legal definition:
1. Empty strings are legal
2. If S is legal, [s] and (s) are legal
3. If A and B are legal, then AB is legal

Title analysis: Make Dp[i][j] indicates the minimum number of parentheses to add the subsequence from I to J
When the subsequence length is 1 o'clock, dp[i][i]= 1
When the subsequence length is not 1 o'clock two scenarios:
1) dp[i] = = ' (' && dp[j] = = ') ' or dp[i]== ' [' && dp[j] = = '] ' indicates that the outer side is legal, then the number of parentheses to be added is determined by the subsequence inside the sub-sequence (dp[i][j] = dp[i + 1][j -1]
2) Enumerate the split points, i.e. I <= K < j,dp[i][j] = min (dp[i][k],dp[k + 1][j])
This will be added to the minimum number can be dp[0][len-1], but the topic to output sequence, so we also want to record the path, if s[i] = = S[j] then path[i][j] = 1, otherwise path[i][j] = k (split point), the output of the use of recursive method, Output mode similar to LCS


#include <cstdio> #include <cstring> int const INF = 0XFFFFFFF;  int const MAX = 105;  int Dp[max][max], Path[max][max];        Char S[max];      void Print (int i, int j) {if (i > J) return;          if (i = = j) {if (s[i] = = ' (' | | s[i] = = ') ') printf ("()");      else printf ("[]");          } else if (path[i][j] = = 1) {printf ("%c", S[i]);          Print (i + 1, j-1);      printf ("%c", S[j]);          } else {Print (i, path[i][j]);      Print (Path[i][j] + 1, j);          }} int main () {while (gets (s)) {int n = strlen (s);              if (n = = 0) {printf ("\ n");          Continue          } memset (DP, 0, sizeof (DP));          for (int i = 0; i < n; i++) dp[i][i] = 1; for (int l = 1, l < n; l++) {for (int i = 0; i < n-l; i++) {in       T j = i + L;           DP[I][J] = INF; if ((s[i] = = ' (' && s[j] = = ') ') | |                  (S[i] = = ' [' && s[j] = = '] '))                      {Dp[i][j] = dp[i + 1][j-1];                  PATH[I][J] =-1; } for (int k = i; k < J; k++) {if (Dp[i][j] > dp[i][k] + dp[k                          + 1][j]) {dp[i][j] = Dp[i][k] + dp[k + 1][j];                      PATH[I][J] = k;          }}}} Print (0, n-1);      printf ("\ n");  }  }






South Mail algorithm analysis and Design Experiment 2 dynamic programming method

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.