题目传送门: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;
}