动态规划:最长公共子序列

问题描述

一个给定序列的子序列是在该序列中删去若干元素后得到的序列。确切地说,若给定序列 X={x1,x2,,xm} , 则另一序列 Z={z1,z2,,zk} , 是X的子序列是指存在一个严格递增下标序列 {i1,i2,,ik} , 使得对于所有的j = 1, 2, , k有: zj=xij 。例如, 序列 Z=B,C,D,B 是序列 X={A,B,C,B,D,A,B} 的子序列, 相应的递增下标序列为 {2,3,5,7}
给定两个序列X和Y,当另一序列Z即是X的子序列又是Y的子序列时,称Z是序列X和Y的公共子序列。
最长公共子序列问题:给定两个序列 X={x1,x2,,xm} Y={y1,y2,,yn} , 找出X和Y的最长公共子序列。

解题思路

设序列 X={x1,x2,,xm} Y={y1,y2,,yn} 的最长公共子序列为 Z={z1,z2,,zk} ,则
1. 若 xm=yn,zk=xm=yn,Zk1Xm1Yn1 的最长公共子序列。
2. 若 xmyn , 且 zkxm , 则 ZXm1Y 的最长公共子序列。
3. 若 xmyn , 且 zkyn , 则 ZXYn1
其中, Xm1={x1,x2,,xm1}Yn1={y1,y2,,ym1}Zk1={z1,z2,,zk1} ;
根据上面的关系建立一个递推关系。 用c[i][j]记录序列 Xi Yj 的最长公共子序列的长度。其中, Xi={x1,x2,,xi} , Yj={y1,y2,,yj} 。可建立如下的递归关系:

c[i][j]=0c[i1][j1]+1max{c[i][j1],c[i1][j]}i = 0, j = 0i, j > 0; xi=yii, j > 0; xiyj

则对于序列

XY 的最长公共子序列长度为:


ans=c[m][n]

代码

#include <stdio.h>
#include <stdlib.h>
#define maxn 100

int c[maxn][maxn];      //保存最长公共子序列的长度
int b[maxn][maxn];     //记录c[i][j]的值是由哪一个子问题的解得到的

void LCS(char x[], char y[], int m, int n);
void PrintLCS(char x[], int i, int j);

int main()
{
    char x[7] = "ABCBDAB";
    char y[6] = "BDCABA";
    printf("最长公共子序列为:");
    LCS(x, y, 7, 6);
    printf("\n\n\n");
    int i, j;
    for (i = 0; i <= 7; i++)
    {//打印二维表
        for (j = 0; j <= 6; j++)
            printf("%3d", c[i][j]);
        printf("\n");
    }
    printf("\n");
    return 0;
}

void LCS(char x[], char y[], int m, int n)
{
    int i, j;
    for (i = 1; i <= m; i++)
        c[i][0] = 0;
    for (i = 1; i <= n; i++)
        c[0][i] = 0;

    for (i = 1; i <= m; i++)
    {
        for (j = 1; j <= n; j++)
        {
            if (x[i-1] == y[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] = 3;
            }
        }
    }
    PrintLCS(x, m, n);  //打印最长公共子序列
}

void PrintLCS(char x[], int i, int j)
{
    if (i == -1 || j == -1)
        return;
    if (b[i][j] == 1)
    {
        PrintLCS(x, i - 1, j - 1);
        printf("%c", x[i-1]);
    }
    else if (b[i][j] == 2)
        PrintLCS(x, i - 1, j);
    else
        PrintLCS(x, i, j - 1);
}
    原文作者:动态规划
    原文地址: https://blog.csdn.net/FD1247/article/details/70231253
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞