动态规划作业-最长公共子序列问题

霜天晓角知教 2018-05-12

问题:对给定序列X=(x1,x2,...xm)和序列Z=(z1,z2,...zk),Z是X的子序列当且仅当存在一个递增下标序列(i1,i2,...ik)

使得对于所有j=1,2,,,k有zj=xij(1<=xij<=m)。例如序列(a,b,c,b,d,a,b)的一个子序列(b,c,d,b)

相应的递增下标序列(2,3,5,7)

给定两个序列X和Y,当序列Z既是X的子序列又是Y的子序列时,称Z是序列X和Y的公共子序列

定义子问题:设L(m,n)表示序列X=(x1,x2,...xm和Y=(y1,y2,...yn)的最长公共子序列的长度,显然

初始子问题是序列X和Y至少有一个空序列,即:

L(0,0)=L(0,j)=L(i,0)=0, 1<=i<=m,1<=j<=n

动态规划函数:

L(i,j)=L(i-1,j-1)+1 xi=yj,i>=1,j>=1

L(i,j)=max{(L(i-1,j),L(i,j-1)} xi!=yj,i>=1,j>=1

为了得到序列X和Y的最长公共子序列,设二维表S(m,n)记载求解过程中的状态变化

S(i,j)=1 xi=yj

S(i,j)=2 xi!=yj,L(i,j-1)>=L(i-1,j)

S(i,j)=3 xi!=yj, L(i,j-1)<L(i-1,j)

若S(i,j)=1,则下一个搜索方向是S(i-1,j-1)

若S(i,j)=2,则下一个搜索方向是S(i,j-1)

若S(i,j)=3则下一个搜索方向是S(i-1,j)

算法:

输入:两个序列x和y

输出:最长公共子序列及其长度

1.循环变量i从0到l1重复下列操作

L[i][0]=S[i][0]=0;

2.循环变量i从0到l2重复下列操作

L[0][i]=S[0][i]=0;

3.循环变量i从1到l1重复下列操作

3.1循环变量j从1到l2

3.1.1如果x[i]==y[j]

S[i][j]=1; L[i][j]=L[i-1][j-1]+1

3.1.2否则如果 L[i][j-1]>=L[i-1][j]

S[i][j]=2; L[i][j]=L[i][j-1]

3.1.3否则 S[i][j]=3;L[i][j]=L[i-1][j]

4.使i=l1,j=l2,k=0;直到i<0 或者j<0,用字符数组path记录最长公共子序列

4.1如果S[i][j]==1 path[k++]=x[i],i--,j--;

4.2否则,如果S[i][j]=2 j--;

4.3否则 i--;

void dp_com(char x[], char y[],int l1,int l2) {
    int L[][];
    int S[][];
    char path[];
    for (int i = ; i <=l1; i++)
        L[i][] = S[i][] = ;
    for (int i = ; i <=l2; i++)
        L[][i] = S[][i] = ;
    for (int i = ; i <=l1; i++) {
        for (int j = ; j <=l2; j++) {
            if (x[i] == y[j]) {
                S[i][j] = ;
                L[i][j] = L[i - ][j - ] + ;
            }
            else if (L[i][j-] >=L[i-][j]) {
                S[i][j] = ;
                L[i][j] = L[i][j-];
            }
            else {
                S[i][j] = ;
                L[i][j] = L[i-][j];
            }
        }
    }
    cout << L[l1][l2] << endl;
    int i = l1, j = l2;
    int k = ;
    while (i > && j >) {
        if (S[i][j] == ) {
            path[k++] = x[i];
            i--;
            j--;
        }
        else if (S[i][j] == ) j--;
        else i--;
    }
    for (i = k-; i >= ; i--)
        cout << path[i];
    cout << endl;
}

相关推荐