题目传送门:https://vjudge.net/problem/51Nod-1006
dp的经典之一:
用如下定义试试看:
dp[i][j] : str11~str1i 和 str21~str2j对应的LCS的长度
由此,str11~str1i+1 和 str21~str2j+1对应的公共子序列可能是:
1. 当str1 =str2时,在str11~str1i 和 str21~str2j的公共子列末尾追加上str1i+1
2. 当str1 !=str2时 (图片上面的s就是str1,t就是str2)
综合来说:
for(int i = 0; i < len1; i++)
{
for(int j = 0; j < len2; j++)
{
if(str1[i] == str2[j])
{
dp[i + 1][j + 1] = dp[i][j] + 1;
}
else
{
dp[i + 1][j + 1] = max(dp[i][j + 1], dp[i + 1][j]);
}
}
}
题目上面,需要输出子串,所以要加一个path记录路径。
其实,这些东西大都是一些套路问题,很多博客都是不讲的,如果有人不明白,怎么加路径,就去参考我的另外一篇博客,里面有一个最短路的课件,里面介绍了路径path怎么用。但是,对于初学者很难理解啦!所以记住得了!
博客地址:http://blog.csdn.net/newproblems/article/details/76472749
完整代码:
#include <algorithm> #include <iostream> #include <cstring> #include <cstdlib> #include <cstdio> #include <cmath> #include <queue> #include <set> #include <map> #define N 1005 using namespace std; char str1[N], str2[N]; int dp[N][N]; int path[N][N]; void dfs(int i, int j) { if(i == 0 || j == 0) return ; if(path[i][j] == 1) { dfs(i - 1, j - 1); printf("%c", str1[i]); } else if(path[i][j] == 2) { dfs(i - 1, j); } else { dfs(i, j - 1); } } int main(void) { scanf("%s%s", str1 + 1, str2 + 1); memset(dp, 0, sizeof(dp)); memset(path, 0, sizeof(path)); int len1 = strlen(str1 + 1); int len2 = strlen(str2 + 1); for(int i = 1; i <= len1; i++) { for(int j = 1; j <= len2; j++) { if(str1[i] == str2[j]) { dp[i][j] = dp[i - 1][j - 1] + 1; path[i][j] = 1; } else { if(dp[i][j - 1] > dp[i - 1][j]) { dp[i][j] = dp[i][j - 1]; path[i][j] = 3; } else { dp[i][j] = dp[i - 1][j]; path[i][j] = 2; } } } } dfs(len1, len2); printf("\n"); return 0; }