C language (CED) ---- longest common subsequence dynamic programming first question

Similarities and differences between a dynamic programming algorithm to divide and conquer method

The same point :

A, both of which are problems to be solved is divided into several sub-problems to solve.          

B, both in the preparation of the code, should be used recursively .

Different points :

A, divide and conquer problem solving, after the problem is divided into several sub-problems, among which is the sub-problems exist independently of, not interrelated . The linkages between sub-problems after dynamic programming problem of division.

B, dynamic programming problem solving requires a table to record the answer to sub-problem has been resolved, thus avoiding a lot of double counting. Dynamic programming algorithm is suitable for solving an optimization problem. This indicates that this type of optimization problem solution may be many, but not necessarily optimal solution, and the use of this algorithm to find the solution may still be the optimal solution in a number of

Second, the structural properties of the optimal solution

Optimal substructure: When the optimal solution contains a sub-optimal solution of its problems, said the problem has structural sub-optimal.

Overlapping sub-problems: in a recursive algorithm to solve the problem from the top down, when each sub-problem is not always generated new problems, some sub-problems are repeatedly calculated. Dynamic programming algorithm formal use of this sub-overlapping nature of the problem, the solution only once for each sub-question, and save it in the table.

In a general sense, the problem has two important properties of the basic elements of the problem can be solved dynamic programming algorithm.

Third, the analysis of dynamic programming problems and troubleshooting steps

A, find the optimal solution properties, which characterize structural features.

B, the optimum value defined recursively

C, calculate the optimal value of the bottom-up (just a result of the optimal value, the optimal solution is a process)

D, configuration information obtained in accordance with the optimal solution (AC into this step is a dynamic programming algorithm, this step is necessary to obtain the optimal solution to the problem needs to be performed only)

Well, the basics of dynamic programming With the above, we began this paper "key" - the longest common subsequence.

Fourth, the description of the problem (question to the effect)

Sequences: a given sequence, the sequence obtained after removing several elements, the sequence is a subsequence.

Public sequence: If two sequences follow the same sequences obtained after the above steps, then the sub-sequence is referred to these two sequences common subsequence.

Example: There are the following two sequences

X={A、B、C、B、D、A、B},Y={B、D、C、A、B、A}

Z = {B, C, A } is a common subsequence of both the sequence, then what is the longest common subsequence , we should know it?

It should be noted here: a sequence of length n, it is a total of 2 ^ n subsequences with (2 ^ n - 1) non-empty sequence. It should be noted here that the sequence and the original sequence associated, rather than high schools learned unordered collection.

Follow the steps below to dynamic programming algorithm design to design algorithms to solve this problem

1, structural problems

 After the above proved that the problem of sub-optimal structural properties.

2, recursive structure

To find X = {x1, x2, ..., xm} and Y = {y1, y2, ..., yn} of the longest common subsequence, recursively as follows:

A, when Xm = Yn, find the longest common subsequence of Xm-1 and Yn-1, and then its tail plus Xm (Xm = Yn), to obtain X, Y of the longest common subsequence.

B, when Xm! When = Yn, then have to deal with two sub-problems: Xm-1 and Y is a longest common subsequence X and Yn-1 and a longest common subsequence, the longer is the best in both the X and Y long common subsequence.

From this recursive structure, the problem with overlapping proton problems, for example: when calculating the longest common subsequence of X and Y, X may be calculated, and Yn-1 and Xm-1 and Y is the longest common subsequence , comprising two sub-problems are a common sub-problems, i.e., to calculate the longest common subsequence of Xm-1 and Yn-1.

Firstly, the relationship between the sub-problems recursively the optimal value, with the c [i] [j] recorded longest common subsequence length sequence Xi and Yi. Wherein, Xi = {x1, x2, ..., xi}; Yj = {y1, y2, ..., yj}

When i = 0 or j = 0, empty sequence is the longest common subsequence of Xi and Yj, so in this case c [i] [j] = 0;

Other situations:

A、i>0;j=0时,c[i][j]=0;

B、i,j>0;Xi=Yj时,c[i][j]=c[i-1][j-1]+1

C、i,j>0;Xi!=Yj时,c[i][j]=max{c[i][j-1],c[i-1][j]}

3, to calculate the optimal value

Directly using the recursive formula write code. Wherein X, Y inputs of the two sequences,, b [i] [j] recorded c [i] [j] value is a solution which come from the sub-problem, which is configured to be at the longest common subsequence used.

void LCSLength(int m,int n,char x[],char y[],int c[][50],int b[][50])
{
    int i,j;
    for(i=1;i<=m;i++)//当j=0时,c[i][j]=0
        c[i][0]=0;
    for(j=1;j<=n;j++)//当i=0时,c[i][j]=0
        c[0][j]=0;
    for(i=1;i<=m;i++)//对最长公共子序列的长度进行记录
        for(j=1;j<=n;j++)
    {
        if(x[i]==y[j])//Xi=Yj的情况
        {
            c[i][j]=c[i-1][j-1]+1;//c[i][j]存储Xi和Yj的最长公共子序列的长度
            b[i][j]=1; //斜向上           //b[i][j]记录c[i][j]的值是由哪个子问题的解得来的
        }
        else if(c[i-1][j]>=c[i][j-1])
        {
            c[i][j]=c[i-1][j];
            b[i][j]=2;//竖直向上
        }
        else
        {
            c[i][j]=c[i][j-1];
            b[i][j]=3;//水平向左
        }
    }
}

4, the configuration of the longest common subsequence

Rapid construction longest common subsequence sequences X and Y two-dimensional array b. First, from b [m] [n] is searched for in the array b in accordance with its value.

A, when b [i] [j] = 1, represents the longest common subsequence Xi and Yi Xi-1 is the longest common subsequence of Yi-1 and adding at the end of Xi obtained.

B, when the b [i] [j] = 2, represents the same longest common subsequence longest common subsequence Xi and Xi-1 and Yj and Yj is.

C, when b [i] [j] 3 = when, Xi and Yj represent like the longest common subsequence of Xi and Yj-1 of the longest common sequence.

Thus, the longest common subsequence printed. code show as below:

void LCS(int i,int j,char x[], int b[][50])
{
    if(i==0||j==0)
        return;
    if(b[i][j]==1)//表示Xi和Yi的最长公共子序列是由Xi-1和Yi-1的最长公共子序列在尾部加上Xi所得到的
        {//b[i][j]==1时,表示左斜45°向上,也即这个时候对应的字母时LCS中的一个。
            LCS(i-1,j-1,x,b);
            cout<<x[i]<<" ";
        }
    else if(b[i][j]==2)//表示Xi和Yj的最长公共子序列与Xi-1和Yj的最长公共子序列相同。
            LCS(i-1,j,x,b);
    else//表示Xi和Yj的最长公共子序列与Xi和Yj-1的最长公共子序列相同。
            LCS(i,j-1,x,b);
}

Therefore, all the steps above into a complete code is as follows:

#include<stdlib.h>
#include<stdio.h>
#include<iostream>
using namespace std;
int c[50][50];
int b[50][50];
char x[1000];//存放X字符串
char y[1000];//存放Y字符串
void LCSLength(int m,int n,char x[],char y[],int c[][50],int b[][50])
{
    int i,j;
    for(i=1;i<=m;i++)//当j=0时,c[i][j]=0
        c[i][0]=0;
    for(j=1;j<=n;j++)//当i=0时,c[i][j]=0
        c[0][j]=0;
    for(i=1;i<=m;i++)//对最长公共子序列的长度进行记录
        for(j=1;j<=n;j++)
    {
        if(x[i]==y[j])//Xi=Yj的情况
        {
            c[i][j]=c[i-1][j-1]+1;//c[i][j]存储Xi和Yj的最长公共子序列的长度
            b[i][j]=1; //斜向上           //b[i][j]记录c[i][j]的值是由哪个子问题的解得来的
        }
        else if(c[i-1][j]>=c[i][j-1])
        {
            c[i][j]=c[i-1][j];
            b[i][j]=2;//竖直向上
        }
        else
        {
            c[i][j]=c[i][j-1];
            b[i][j]=3;//水平向左
        }
    }
}
void LCS(int i,int j,char x[], int b[][50])
{
    if(i==0||j==0)
        return;
    if(b[i][j]==1)//表示Xi和Yi的最长公共子序列是由Xi-1和Yi-1的最长公共子序列在尾部加上Xi所得到的
        {//b[i][j]==1时,表示左斜45°向上,也即这个时候对应的字母时LCS中的一个。
            LCS(i-1,j-1,x,b);
            cout<<x[i]<<" ";
        }
    else if(b[i][j]==2)//表示Xi和Yj的最长公共子序列与Xi-1和Yj的最长公共子序列相同。
            LCS(i-1,j,x,b);
    else//表示Xi和Yj的最长公共子序列与Xi和Yj-1的最长公共子序列相同。
            LCS(i,j-1,x,b);
}
int main()
{
    int xn,yn;//XY字符串的大小
    cout<<"请输入X集合的元素个数:"<<endl;
    cin>>xn;
    cout<<"请输入X集合的元素:"<<endl;
    int i=0;//用于循环输入X和Y的字符串
    for(i=1;i<=xn;i++)
        cin>>x[i];
    cout<<"请输入y集合的元素个数:"<<endl;
    cin>>yn;
    cout<<"请输入y集合的元素:"<<endl;
    for(i=1;i<=yn;i++)
        cin>>y[i];
    LCSLength(xn,yn,x,y,c,b);
	cout << "X和Y的最长公共子序列为:";
    LCS(xn,yn,x,b);
	cout << endl;
	
	int j = 0;
	int m = 0;
	printf("b[i][j]中的数字:\n");
	for (i = 0; i <=xn; i++)
		for (j = 0; j <= yn; j++)
		{ 
			printf("%d ", b[i][j]);
			m++;
			if (m == xn)
			{
				m = 0;
				printf("\n");
			}
				  
		}
	m = 0;
	printf("c[i][j]中的数字:\n");
	for (i = 0; i <= xn; i++)
		for (j = 0; j <=yn; j++)
		{
			printf("%d ", c[i][j]);
			m++;
			if (m == xn)
			{
				printf("\n");
				m = 0;

			}
				
		}	
	system("pause");
    return 0;
}

After the c [i] [j] and b [i] [j] in association with, to give the following figure:

As can be seen from the figure, information with a two-dimensional array b [i] [j] can be constructed in a longest common subsequence of X and Y. From b [xn] [yn] starts tracking the direction of arrow orange:

When A, b [i] [j] equal to 1, 45 ° left oblique jump up and off the LCS is a member of the letters

B, b [i] [j] equal to 2, vertical jump up.

C, b [i] [j] equal to 3, the horizontal leftward jump.

Reference: "computer algorithm design and analysis · Fifth Edition" edited by Wang Xiaodong

Published 62 original articles · won praise 93 · views 120 000 +

Guess you like

Origin blog.csdn.net/GenuineMonster/article/details/88877229
Recommended