最长公共子序列

这两天都在看基础的动态规划,讲到最长公共子序列的时候,想起了很多以前做过的OJ上的题,但是当时想法太差只会暴力循环而且没做对,所以话了点时间整理

《算法导论》中第十五章说:一个给定序列的子序列就是该给定序列中去掉0个或者多个元素。以形式化的方式来说,给定一个序列X=X[1],X[2].....X[m],另一个序列Z=Z[1],Z[2].....Z[k]是X的子序列,如果存在X的一个严格递增下标序列<i1,i2.....ik>,使得对所有的j=1 2.....k有X[i]=Z[j]。

例子:Z=BCDB 是X=ABCBDAB的一个子序列,相对应的下标序列为2 3 5 7

给定两个序列X和Y,如果Z既是X的一个子序列,又是Y的一个子序列,则称序列Z是X和Y的公共子序列(这里我觉得中文版翻译的顺序错了,所以我改了下句子的顺序)。

例子是:假设两个字符串X,Y  X="ABCBDAB"  Y="BDCABA"

则他们的最大公共子序列 是"BCBA"

这个问题可以用动态规划来解决

 

#include<stdio.h>
#include<string.h>
void turn(char A[],char tA[])                                                   //将A复制放在tA,不过tA的0位置是没东西 
{                                                                               //比如说  A :ABCDEFG\0 
    int len=strlen(A);                                                          //那么tA变成: ABCDEFG\0 
    tA[0]=' ';                                                                  //这样做的原因是 数组下标从0开始     
    for(int i=0;i<len;i++)                                                      //所以将A[1]要变成字符的开头 
    {
        tA[i+1]=A[i];
    } 
    tA[len+1]='\0';
}

void LCSlength(char A[],char B[],int c[][50],int b[][50])                       //c数组是记录 记录公共子序列的长度 
{
    int lena=strlen(A)-1,lenb=strlen(B)-1;
    for(int i=0;i<=lena;i++)c[i][0]=0;
    for(int i=0;i<=lenb;i++)c[0][i]=0;
    for(int i=1;i<=lena;i++)
    {
        for(int j=1;j<=lenb;j++)
        {
            if(A[i]==B[j])                                                      //当遇到能够构成更长的子序列的时候+1 
            {
                c[i][j]=c[i-1][j-1]+1;
                b[i][j]=1;
            }
            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]=0;
            }
        }
    }
}

void printLCS(int b[][50],char A[],int i,int j)                                  //输出最长公共子序列 
{
    if(i==0||j==0)return ;
    if(b[i][j]==1)
    {
        printLCS(b,A,i-1,j-1);
        printf("%c",A[i]); 
    }
    else if(b[i][j]==2)printLCS(b,A,i-1,j);
    else printLCS(b,A,i,j-1);
}

void printMArray(int Array[][50],int x,int y)                                    //监控b / c数组的过程 
{
    for(int i=1;i<=x;i++)
    {
        for(int j=1;j<=y;j++)
        {
            printf("%d ",Array[i][j]);
        }
        printf("\n");
    }
}

int main()
{
    printf("请输入要求最长公共子序列的两个字符串:\n");
    char A[50],B[50];
    char tA[50],tB[50];
    int b[50][50],c[50][50];
    scanf("%s %s",A,B);
    int lenA=strlen(A);
    int lenB=strlen(B);
    turn(A,tA);
    turn(B,tB);
    LCSlength(tA,tB,c,b);
    printMArray(c,lenA,lenB);
    //printMArray(b,lenA,lenB);
    printLCS(b,tA,lenA,lenB);
    return 0;
}

posted on 2012-11-25 18:29  Aquariuslt  阅读(142)  评论(0)    收藏  举报

导航