NYOJ-36 最长公共子序列 动态规划

最长公共子序列

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

动态规则经典题,详细讲解参考算法 导论P208。


01. #include
02. #include
03. using namespace std;
04.  
05. int c[1002][1002];
06.  
07. void lcs(string &a,string &b,int n,int m)
08. {
09. for(int i=0;i<=m;i++)
10. c[0][i]=0;
11. for(int i=0;i<=n;i++)
12. c[i][0]=0;
13. for(int i=1;i<=n;i++)
14. {
15. for(int j=1;j<=m;j++)
16. {
17. if(a[i-1]==b[j-1])
18. c[i][j]=c[i-1][j-1]+1;
19. else if(c[i][j-1]>c[i-1][j])
20. c[i][j]=c[i][j-1];
21. else
22. c[i][j]=c[i-1][j];
23. }
24. }
25.  
26. }
27.  
28. int main()
29. {
30. string a,b;
31. int t;
32. cin>>t;
33. while(t--)
34. {
35. cin>>a>>b;
36. lcs(a,b,a.size(),b.size());
37. cout<
38. }
39. return 0;
40. }

然而上面的算法空间复杂度还是挺大的,算法导论书中习题要求只用min(m,n)+O(1)的空间完成。于是就有了如下的算法:

只用一维数组dp[N]。

old 变量是用来表示dp[i-1][j-1],dp[j-1]表示dp[i][j-1],dp[j]表示dp[i-1][j]。

比如,当我们开始处理i=4的时候,从j=1开始,一开始old表示dp[3][0],肯定为0。然后用临时变量tmp记下这时的dp[j]这时的dp[j]还没有被改变,也就是说,这里的dp[j]还是i=3的时候求得的dp[j],而其对于j+1来说就是dp[i-1][j-1]。此时的dp[j]对当前的j来说,就是dp[i-1][j],而dp[j-1]已经在 j的前一刻被处理过了,也就等阶于dp[i][j-1]。OVER。

#include
02. #include
03. #include
04. using namespace std;
05.  
06. int dp[1001];
07.  
08. int main()
09. {
10. int t;
11. cin>>t;
12. while(t--)
13. {
14. string a,b;
15. cin>>a>>b;
16. memset(dp,0,sizeof(dp));
17. int al=a.size(),bl=b.size();
18. int old,tmp;
19. for(int i=1;i<=al;i++)
20. {
21. old=0;
22. for(int j=1;j<=bl;j++)
23. {
24. tmp=dp[j];
25. if(a[i-1]==b[j-1])
26. dp[j]=old+1;
27. else if(dp[j-1]>dp[j])
28. dp[j]=dp[j-1];
29. old=tmp;
30. }
31. }
32. cout<
33. }
34. return 0;
35. }





你可能感兴趣的:(动态规划)