最长公共子序列(动态规划)

动态申请二维数组:

    int row; //
    int col; //
    cin >> row >> col;

    //动态申请二维数组
    int** p = new int* [row];
    for (int i = 0; i < row; i++) {
        p[i] = new int[col];
    }
    
    //释放二维数组所占用的空间
    for (int i = 0; i < row; i++) {
        delete[] p[i];
    }
    delete[] p;

 

LCS问题即最长公共子序列问题,它不要求所求得的字符在所给的字符串中是连续的(例如:输入两个字符串BDCABA和ABCBDAB,字符串BCBA和BDAB都是是它们的最长公共子序列,则输出它们的长度4,并打印任意一个子序列)

最长公共子序列的结构有如下表示:

    设序列X=<x1, x2, …, xm>和Y=<y1, y2, …, yn>的一个最长公共子序列Z=<z1, z2, …, zk>,则:

1、若xm=yn,则zk=xm=yn且Zk-1是Xm-1和Yn-1的最长公共子序列;
2、若xm≠yn且zk≠xm ,则Z是Xm-1和Y的最长公共子序列;
3、若xm≠yn且zk≠yn ,则Z是X和Yn-1的最长公共子序列。
其中Xm-1=<x1, x2, …, xm-1>,Yn-1=<y1, y2, …, yn-1>,Zk-1=<z1, z2, …, zk-1>。

动态转换方程:

 

由算法LCS_LENGTH计算得到的数组b可用于快速构造序列X=<x1, x2, …, xm>和Y=<y1, y2, …, yn>的最长公共子序列。首先从b[m,n]开始,沿着其中的箭头所指的方向在数组b中搜索。

当b[i,j]中遇到"↖"时(意味着xi=yi是LCS的一个元素),表示Xi与Yj的最长公共子序列是由Xi-1与Yj-1的最长公共子序列在尾部加上xi得到的子序列;
当b[i,j]中遇到"↑"时,表示Xi与Yj的最长公共子序列和Xi-1与Yj的最长公共子序列相同;
当b[i,j]中遇到"←"时,表示Xi与Yj的最长公共子序列和Xi与Yj-1的最长公共子序列相同。

 1 #include<iostream>
 2 //#include<bits/stdc++.h>
 3 #include<cmath>
 4 #include<cstring>
 5 #include<algorithm>
 6 #include<cstdio>
 7 #include<malloc.h>
 8 #include<sstream>
 9 #include<string.h>
10 using namespace std;
11 
12 typedef long long ll;
13 
14 bool cmp(int a, int b) {
15     return a > b;
16 }
17 
18 void OutPutLCS(int** B, string s1, int s1len, int s2len);
19 
20 int main() {
21     string s1, s2;
22     cin >> s1 >> s2;
23     int s1len = s1.length();
24     int s2len = s2.length();
25 
26     //动态申请二维数组
27     int** B = new int* [s1len + 1];
28     for (int i = 0; i <= s1len; i++) {
29         B[i] = new int[s2len + 1];
30     }
31     int** C = new int* [s1len + 1]; //记录最优解值的表
32     for (int i = 0; i <= s1len; i++) {
33         C[i] = new int[s2len + 1];
34     }
35 
36     for (int i = 0; i <= s1len; i++) {
37         C[i][0] = 0;
38         B[i][0] = -2; //-2表示没有方向
39     }
40     for (int i = 0; i <= s2len; i++) {
41         C[0][i] = 0;
42         B[0][i] = -2; //-2表示没有方向
43     }
44     for (int i = 1; i <= s1len; i++) {
45         for (int j = 1; j <= s2len; j++) {
46             if (s1[i - 1] == s2[j - 1]) {
47                 C[i][j] = C[i - 1][j - 1] + 1;
48                 B[i][j] = 0; //0表示斜左上
49             }
50             else {
51                 if (C[i - 1][j] >= C[i][j - 1]) {
52                     C[i][j] = C[i - 1][j];
53                     B[i][j] = -1; //-1表示竖直向上
54                 }
55                 else {
56                     C[i][j] = C[i][j - 1];
57                     B[i][j] = 1; //1表示横向左
58                 }
59             }
60         }
61     }
62     for (int i = 0; i <= s1len; i++) {
63         for (int j = 0; j <= s2len; j++) {
64             cout << C[i][j] << " ";
65         }
66         cout << endl;
67     }
68     cout << endl;
69     for (int i = 0; i <= s1len; i++) {
70         for (int j = 0; j <= s2len; j++) {
71             printf("%2d ", B[i][j]);
72         }
73         cout << endl;
74     }
75     OutPutLCS(B, s1, s1len, s2len);
76     return 0;
77 }
78 
79 void OutPutLCS(int** B, string s1, int s1len, int s2len) {
80     if (s1len == 0 || s2len == 0)
81         return;
82     if (B[s1len][s2len] == 0) //斜左向上
83     {
84         OutPutLCS(B, s1, s1len - 1, s2len - 1);
85         cout << s1[s1len - 1];
86     }
87     else if (B[s1len][s2len] == -1) { //竖直向上
88         OutPutLCS(B, s1, s1len - 1, s2len);
89     }
90     else
91         OutPutLCS(B, s1, s1len, s2len - 1); //横向左
92 }
代码示例

 

最长公共子序列

时间限制:3000 ms  |  内存限制:65535 KB
难度:3
描述
咱们就不拐弯抹角了,如题,需要你做的就是写一个程序,得出最长公共子序列。
tip:最长公共子序列也称作最长公共子串(不要求连续),英文缩写为LCS(Longest Common Subsequence)。其定义是,一个序列 S ,如果分别是两个或多个已知序列的子序列,且是所有符合此条件序列中最长的,则 S 称为已知序列的最长公共子序列。
输入
第一行给出一个整数N(0<N<100)表示待测数据组数
接下来每组数据两行,分别为待测的两组字符串。每个字符串长度不大于1000.
输出
每组测试数据输出一个整数,表示最长公共子序列长度。每组结果占一行。
样例输入
2
asdf
adfsd
123abc
abc123abc
样例输出
3
6
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;

char str1[1005],str2[1005],a[1005],b[1005];
int dp[1005][1005];

int main(){
    int n;
    cin>>n;
    while( n-- ){
        cin>>a;
        cin>>b;
        int len1 = strlen(a);
        int len2 = strlen(b);
        int i,j;
        dp[0][0] = 0; 
        for( i = 0; i < len1; i++ )
            str1[i+1] = a[i];
        for( i = 0; i < len2; i++ )
            str2[i+1] = b[i];
        for( i = 1; i <= len1; i++ )
            for( j = 1; j <= len2; j++ ){
                if( str1[i] == str2[j] )
                    dp[i][j] = dp[i-1][j-1]+1;
                else
                    dp[i][j] = max(dp[i-1][j],dp[i][j-1]);
            } 
            cout<<dp[len1][len2]<<endl;
    }
    return 0;
} 
posted @ 2018-11-29 23:42  无心小男  阅读(429)  评论(0编辑  收藏  举报