zoukankan      html  css  js  c++  java
  • DP问题之最长公共子序列

    问题描述:给定两个序列X=<x1, x2,x3,…,xm> 和 Y=<y1, y2, y3,…, yn>, 求X与Y的一个最长公共子序列

    问题分析:这个题目的阶段不是明显,没有很明显的上一步、上一层之类的。

    既然涉及到公共子序列,也就是有X的第 i 个字符和Y的第 j 个字符相等的情况。

    显然如果X[i] = Y[j] 那么长度分别为 i 和 j 的最长公共子序列就是长度分别为 i-1 和 j-1的最长公共子序列 加上 X[i] 或 Y[j]。

    如果X[i] != Y[j] 呢?

    如果不相等,那么长度为 i 和长度为 j 的序列的最长公共子序列就是“长度为i-1 和 j ” 和“长度为 i 和 j-1 ”中最长公共子序列中较长的一个

    因此可以设计以一个状态opt[i, j] 表示起点为 1 ,长度分别为 i 和 j 的最长公共子序列,状态方程可以写为:

                          opt[i-1, j-1] + x[i]     x[i]  == y[j]

    opt[i, j] =      opt[i-1, j]                   x[i]   != y[j] && Len(opt[i-1, j] ) >= Len(opt[i, j-1])

                          opt[i, j-1]                   x[i]   != y[j] && Len(opt[i-1, j])  < Len(opt[i, j-1]) 

    (0 <= i <= Len(X) && 0 <= j <= Len(Y))

    测试代码:

    #include <stdio.h>
    #include <stdlib.h>
    
    static const int m = 8;
    static const int n = 6;
    char X[8] = {' ','A','B','C','B','D','A','B'}; //X[0] 为了后面写代码方便 
    char Y[6] = {' ','B','D','C','B','A'};
    
    int len[8][6] = {0};  //记录序列1的 i 和序列2的 j 的最长公共子序列的长度 
    int flag[8][6] = {0}; //记录在i和j处的选择,为后面输出最长子序列 
    
    int LCS()
    {
        int i, j;
        
        for(i=1; i<m; i++)
        {
            for(j=1; j<n; j++)
            {
                if(X[i] == Y[j])
                {
                    len[i][j] = len[i-1][j-1] + 1;
                    flag[i][j] = 0;     
                }
                else if(len[i-1][j] >= len[i][j-1])
                {
                    len[i][j] = len[i-1][j];
                    flag[i][j] = 1;   
                }
                else
                {
                    len[i][j] = len[i][j-1];
                    flag[i][j] = 2;
                }
            }        
        }
        return len[m-1][n-1];
    }
    
    void printLCS(int i, int j) 
    {
        if(i==0 || j==0)
            return;
        if(flag[i][j] == 0)
        {
            printLCS(i-1, j-1);
            printf("%c ", X[i]);
        }
        else
        {
            if(flag[i][j] == 1)
                printLCS(i-1, j);
            else
                printLCS(i, j-1);
        }
    }
    
    int main()
    { 
        printf("Longest Common Sequence Length: %d\n", LCS());
        printLCS(m-1, n-1);
        printf("\n");
        return 0;
    }
     
    结果:
    Longest Common Sequence Length: 4
    B C B A
    请按任意键继续. . .
  • 相关阅读:
    最大子序列和问题的几种算法
    给Repeater控件里添加序号的5种方法
    关于上传(上传所用到的upload和upload的应用)
    .net中的动态时钟 (年月日 时分秒)
    网页总结
    PHP算法将数字金额转换成大写金额
    Linux下编译安装redis,详细教程
    如何让PHP支持Redis
    网络互连技术——第一章随记
    网络互连技术——第二章考试需知
  • 原文地址:https://www.cnblogs.com/lovesaber/p/2034063.html
Copyright © 2011-2022 走看看