LCS+路径还原

来源:互联网 发布:网络电话拨号软件 编辑:程序博客网 时间:2024/06/07 01:29

51nod动态规划教程
最后,我们来提供输入输出数据,由你来写一段程序,实现这个算法,只有写出了正确的程序,才能继续后面的课程。

输入

第1行:字符串A
第2行:字符串B
(A,B的长度 <= 1000)

输出

输出最长的子序列,如果有多个,随意输出1个。

输入示例

abcicba
abdkscab

输出示例

abca

图示
思路:
刚开始按照LIS的nlgn解法思路记录路径,发现错多了。LCS更新的方式就是分两种情况(两个字符相等和不相等)和三个方向(左,上,左上)取最大值,dp[i + 1][j + 1]表示的是在A串前i位和B串前j位的LCS(可能不止一个序列,但最大值唯一),由于序列不唯一,路径还原就需要找dp增加的时候来自的两种情况。字符相等的情况才是真正的路径,不相等时只是为了更新这个dp值(为下一个相等时做准备),这样问题就easy了,用二维数组记录dp值增加来自的三个方向,开始逆着搜索,当出现字符相等的情况输出这个字符;

#include <cstdio>#include <cstring>#include <cmath>#include <algorithm>#define max_n 1010using namespace std;int dp[max_n][max_n], pre[max_n][max_n];char A[max_n], B[max_n], C[max_n];void dfs(int x, int y) { //找来自的方向     if(x == 0 || y == 0) return;    else if(pre[x][y] == 1) {        dfs(x - 1, y - 1);        printf("%c", A[x - 1]);    }    else if(pre[x][y] == 2) {        dfs(x - 1, y);    }    else dfs(x, y - 1);}int main() {    memset(pre, 0, sizeof(pre)); //记录dp增加 来自的方向     memset(dp, 0, sizeof(dp));    gets(A);    gets(B);    int len1 = strlen(A);    int len2 = strlen(B);    for(int i = 0; i < len1; i++) {        for(int j = 0; j < len2; j++) {            if(A[i] == B[j]) {                dp[i + 1][j + 1] = dp[i][j] + 1;                pre[i + 1][j + 1] = 1; //来自左上方,下标是字符串下标+1             }            else {                if(dp[i][j + 1] > dp[i + 1][j]) {                    dp[i + 1][j + 1] = dp[i][j + 1];                    pre[i + 1][j + 1] = 2; //来自j + 1;                 }                else {                    dp[i + 1][j + 1] = dp[i + 1][j];                    pre[i + 1][j + 1] = 3; //来自i + 1                 }            }        }    }    dfs(len1, len2);    return 0;} 
原创粉丝点击