最长公共子序列 (LCS,longest common subsequence problem) 动态规划

/*
函数:最长公共子序列 (LCS,longest common subsequence problem)   动态规划解决该问题.


算法见 算法导论  原书第三版  殷建平 P224

一个给定的子序列就是将给定的一个或多个元素去掉之后的结果.
最长公共子序列,求x,y长度最长的公共子序列.

x={x1,x2...xm}   y={y1,y2...yn}
分情况:
1.当xm=yn时,应该求解x(m-1)和y(n-1)的LCS,然后将xm或者yn加到LCS的队尾
2.当xm!=yn时,应求解两个子问题
求x(m-1)和y的LCS和x与y(n-1)的一个LCS
比较两个LCS的长度,取较长者.

覆盖了所有的可能性.

含有共享子问题


时间:15.7.24
Jason Zhou  
热爱你所写下的程序,他是你的伙伴,而不是工具.
*/


#include<iostream>
using namespace std;


int print_arr(char x[],int len)
{
    //int len=sizeof(x)/sizeof(x[0]);
    cout<<"-----------------------len="<<len<<endl;
    for (int i=0;i<len;i++)
    {
        cout<<"  "<<x[i];
    }
    cout<<endl;
    return 0;
}

int ** new_arr(int m,int n)
{

    int **b=new int *[m];
    for (int i=0;i<m;i++)
    {
        b[i]=new int[n];
    }
    return b;
}

int delete_arr(int **b,int m)
{

    for (int di=0;di<m;di++)
    {
        delete [] b[di];
    }
    delete b;

    return 0;
}

int print_lcs(int **b,char x[],char y[],int lx,int ly)
{
    if (lx==-1 || ly==-1)
    {
        return 0;
    }
    if (1==b[lx-1][ly-1])
    {
        print_lcs(b,x,y,lx-1,ly-1);
        cout<<" "<<x[lx-1];
    }
    else if (2==b[lx-1][ly-1])
    {
        print_lcs(b,x,y,lx-1,ly);
    }
    else
    {
        print_lcs(b,x,y,lx,ly-1);
    }

    return 0;
}

int lcs_length(char x[],int lenx,char y[],int leny)
{
    int m=lenx;
    int n=leny;
    int **b=new_arr(m,n);
    int **c=new_arr(m+1,n+1);

    for (int i=0;i<m+1;i++)
    {
        c[i][0]=0;
    }
    for (int j=1;j<n+1;j++)
    {
        c[0][j]=0;
    }

    for (int i=1;i<m+1;i++)
        for(int j=1;j<n+1;j++)
        {
            if (x[i-1]==y[j-1])
            {
                c[i][j]=c[i-1][j-1]+1;
                b[i-1][j-1]=1;//代表指向左上
            }
            else if(c[i-1][j]>=c[i][j-1])
            {
                c[i][j]=c[i-1][j];
                b[i-1][j-1]=2;//代表指向上
            }
            else
            {
                c[i][j]=c[i][j-1];
                b[i-1][j-1]=3;//代表指向左
            }
        }



        cout<<"#c---------------------"<<endl;
        for (int i=0;i<m+1;i++)
        {
            for(int j=0;j<n+1;j++)
            {
                cout<<" "<<c[i][j];
            }
            cout<<endl;
        }


        cout<<"#b---------------------"<<endl;
        for (int i=0;i<m;i++)
        {
            for(int j=0;j<n;j++)
            {
                cout<<" "<<b[i][j];
            }
            cout<<endl;
        }

        cout<<"最长公共子序列-------------"<<endl;
        print_lcs(b,x,y,m,n);
        delete_arr(b,m);
        delete_arr(c,m+1);
        cout<<endl;


        return 0;
}

int main()
{
    char x[]={'a','b','c','b','d','a','b'};
    char y[]={'b','d','c','a','b','a'};


    int len1=sizeof(x)/sizeof(x[0]);
    print_arr(x,len1);
    int len2=sizeof(y)/sizeof(y[0]);
    print_arr(y,len2);

    lcs_length(x,len1,y,len2);

    return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值