作业9——动态规划求解LCS

1.问题

给定向量 X = < X 1 , X 2 , . . . , X n > {X=<X_1,X_2,...,X_n>} X=<X1,X2,...,Xn> Y = < Y 1 , Y 2 , . . . Y m > {Y=<Y_1,Y_2,...Y_m>} Y=<Y1,Y2,...Ym>
求解X和Y的最长公共子序列

2.解析

设dp[i][j]为X的前i位和Y的前j位的LCS的长度,path[i][j]为记录dp[i][j]所采取的决策,1为删掉X的第i位,2为删掉Y的第j位,3为分别删掉X,Y的i,j位
由此可以推出dp方程,当i=0||j=0时,dp[i][0]=dp[0][j]=0;当i>=1&&j>=1时,再分类讨论,当X[i]==Y[j]时,dp[i][j]=dp[i-1][j-1]+1;当X[i]!=Y[j]时,dp[i][j]=max(dp[i-1][j],dp[i][j-1]),同时根据dp[i][j]的选择策略决定path[i][j]的值,当dp[i-1][j]>dp[i][j-1],说明在X[i],Y[j]不相等时,当前序列可以选择删除i位得到dp[i-1][j]的LCS的长度,dp[i-1][j]<=dp[i][j-1]同理。
例子:
在这里插入图片描述
在这里插入图片描述

3.设计

int dp[MAXN][MAXN], path[MAXN][MAXN];
stack<int>sta;
void find_LCS(int X[], int Y[], int n, int m)//递归求解LCS序列中具体的数
{
    if (!n || !m) return;
    if (path[n][m] == 1)//1代表需删除X序列中的最后一位
        find_LCS(X, Y, n - 1, m);
    else if (path[n][m] == 2)//2代表需删除Y序列中的最后一位
        find_LCS(X, Y, n, m - 1);
    else if (path[n][m] == 3)//3代表X[n-1]=Y[m-1]
    {
        sta.push(X[n - 1]);
        find_LCS(X, Y, n - 1, m - 1);
    }
}
void LCS(int X[], int Y[], int n, int m)//求解LCS
{
    memset(dp, 0, sizeof(dp));//初始化
    memset(path, 0, sizeof(path));
    for (int i = 1; i <= n; i++) 
        for (int j = 1; j <= m; j++)
        {
            if (X[i - 1] == Y[j - 1])
            {
                dp[i][j] = dp[i - 1][j - 1] + 1;
                path[i][j] = 3;//代表X[i-1]和Y[j-1]相等
            }
            else
            {
                if (dp[i - 1][j] > dp[i][j - 1])
                {
                    dp[i][j] = dp[i - 1][j];
                    path[i][j] = 1;//删除X[i-1]更优
                }
                else
                {
                    dp[i][j] = dp[i][j - 1];
                    path[i][j] = 2;//删除Y[j-1]更优
                }
            }
        }
    printf("最长公共子序列的长度=%d\n", dp[n][m]);
    find_LCS(X, Y, n, m);//递归求解LCS序列中具体的数
    while (!sta.empty()) //输出
    {
        printf("%d\t", sta.top());
        sta.pop();
    }
}

4.分析

从代码中我们很容易得出,双重循环,时间复杂度为O(nm),并且寻找LCS序列的递归算法的时间复杂度也小于O(nm),所以该算法总的时间复杂度为O(nm)

5.源码

Github

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值