这道题被51Nod定为基础题(这要求有点高啊),我感觉应该可以算作一级或者二级题目,主要原因不是动态规划的状态转移方程的问题,而是需要理解最后的回溯算法。

  

  题目大意:找到两个字符串中最长的子序列,子序列的要求满足其中字符的顺序和字母在两个序列中都必须相同,任意输出一个符合题意的子序列

  首先是最基本的最长公共子序列的状态转移问题

  

  这里的maxLen[i][j]数组的意思就是保存s1的前 i 个字符和s2的前 j 个字符匹配的状态。

  举个例子:maxLen[3][6]即表明在s1的前3个字符和s2的前6个字符中匹配到的最长公共子序列的长度。

    如果能够理解这里,那么动态规划的“无后效性”这一关键性质也就理解了,动态规划的关键就在于找到一个合理的最优状态使得其在后续的状态转移中不会被影响,而其状态就是题设最优问题的子优化问题,这样的状态就得以让我们逐步向父优化问题递进。

  基于此可以将maxLen[i-1][j-1]作为maxLen[i][j]的子问题

    当s1的第 i 字符和s2的第 j 字符匹配时有状态转移方程:maxLen[i][j] = maxLen[i-1][j-1] + 1

  而maxLen[i-1][j]maxLen[i][j-1]则是在i和j不匹配时将前一个状态的最优解传递给下一状态

    即不匹配时有状态转移方程:maxLen[i][j] = max(maxLen[i-1][j], maxLen[i][]j-1)

  以下给出基于此状态转移方程的计数代码

  1. //两字符串中找出一个最长字符串
  2. //ps:其字符在两字符串中存在且顺序相同-记录字符个数
  3.  
  4. #define max(x,y) ((x)>(y)?(x):(y))
  5.  
  6. int maxlen[MAX][MAX]; //s1前i个字符和s2前i个字符最长匹配
  7.  
  8. int Matching(char s1[],char s2[])
  9. {
  10. memset(maxlen, , sizeof(maxlen));
  11. int len1 = strlen(s1);
  12. int len2 = strlen(s2);
  13. for (i = ; i <= len1; i++)
  14. for (j = ; j <= len2; j++)
  15. if (s1[i - ] == s2[j - ]) //s1前i与s2前j字符串尾字符匹配
  16. maxlen[i][j] = maxlen[i - ][j - ] + ;
  17. else //不匹配
  18. maxlen[i][j] = max(maxlen[i][j - ], maxlen[i - ][j]);
  19. return maxlen[len1][len2];
  20. }e

  接着是该题最重要的回溯算法,这一步是输出子序列的关键:

    借用一张图描述该算法思路如下:

    

    要从标明了各状态的二维数组中找出子序列的方法可以作如下描述:

      当父状态maxLen[i][j]和最相近的两个子状态maxLen[i-1][j]maxLen[i][j-1]都不相同的时候

        说明此时maxLen[i][j]做了该运算:maxLen[i][j] = maxLen[i-1][j-1] + 1

      当父状态maxLen[i][j]和最相近的两个子状态中任一个相同的时候

        说明此时maxLen[i][j]做了该运算:maxLen[i][j] = max(maxLen[i-1][j], maxLen[i][]j-1)  

    

    需要注意的是在父状态和最近子状态都相同时将衍生平移的两个方向,由此可以得出所有最长公共子序列的集合

    由于该题只需要输出任一个,因此指定一个方向回溯即可。


  因此合并上述的两个算法可以得出该题的最终算法:

  

  1. //求出最长公共子序列并输出任一子序列
  2. #include <cstdio>
  3. #include <cstring>
  4. #include <iostream>
  5. using namespace std;
  6.  
  7. #define MAX 1001
  8. #define max(x,y) ((x)>(y)?(x):(y))
  9.  
  10. char s1[MAX], s2[MAX];
  11. int maxLen[MAX][MAX];
  12. char ans[MAX];
  13.  
  14. int main()
  15. {
  16. int k = ;
  17. scanf("%s%s", s1,s2);
  18. int len1 = strlen(s1);
  19. int len2 = strlen(s2);
  20.  
  21. for (int i = ; i <= len1; i++)
  22. {
  23. for (int j = ; j <= len2; j++)
  24. {
  25. if (s1[i-] == s2[j-])
  26. maxLen[i][j] = maxLen[i - ][j - ] + ;
  27. else maxLen[i][j] = max(maxLen[i][j - ], maxLen[i-][j]);
  28. }
  29. }
  30.  
  31. int i = len1;
  32. int j = len2;
  33. while(i)
  34. {
  35. if (maxLen[i][j] > maxLen[i - ][j])
  36. {
  37. if (maxLen[i][j] > maxLen[i][j - ])
  38. ans[maxLen[i][j] - ] = s1[i - ];
  39. else i++; //左平移
  40. j--; //减小一个规模
  41. }
  42. i--; //上平移
  43. }
  44.  
  45. printf("%s\n", ans);
  46. return ;
  47. }

ACM/ICPC 之 最长公共子序列计数及其回溯算法(51Nod-1006(最长公共子序列))的更多相关文章

  1. 51nod 1006 最长公共子序列Lcs 【LCS/打印path】

    1006 最长公共子序列Lcs  基准时间限制:1 秒 空间限制:131072 KB 分值: 0 难度:基础题  收藏  关注 给出两个字符串A B,求A与B的最长公共子序列(子序列不要求是连续的). ...

  2. 51nod 1006 最长公共子序列Lcs(经典动态规划)

    传送门 Description 给出两个字符串A B,求A与B的最长公共子序列(子序列不要求是连续的).   比如两个串为:   abcicba abdkscab   ab是两个串的子序列,abc也是 ...

  3. 51Nod - 1006 最长公共子序列Lcs模板

    给出两个字符串A B,求A与B的最长公共子序列(子序列不要求是连续的).   比如两个串为:   abcicba abdkscab   ab是两个串的子序列,abc也是,abca也是,其中abca是这 ...

  4. (DP)51NOD 1006 最长公共子序列&1092 回文字符串

    1006 给出两个字符串A B,求A与B的最长公共子序列(子序列不要求是连续的). 比如两个串为:   abcicba abdkscab   ab是两个串的子序列,abc也是,abca也是,其中abc ...

  5. 51Nod 1006 最长公共子序列Lcs问题 模板题

    给出两个字符串A B,求A与B的最长公共子序列(子序列不要求是连续的). 比如两个串为:   abcicba abdkscab   ab是两个串的子序列,abc也是,abca也是,其中abca是这两个 ...

  6. 51NOD 1006 最长公共子序列 Lcs 动态规划 DP 模板题 板子

    给出两个字符串A B,求A与B的最长公共子序列(子序列不要求是连续的). 比如两个串为: abcicba abdkscab ab是两个串的子序列,abc也是,abca也是,其中abca是这两个字符串最 ...

  7. 【模板】51nod 1006 最长公共子序列Lcs

    [题解] dp转移的时候记录一下,然后倒着推出答案即可. #include<cstdio> #include<cstring> #include<algorithm> ...

  8. 【转】lonekight@xmu·ACM/ICPC 回忆录

    转自:http://hi.baidu.com/ordeder/item/2a342a7fe7cb9e336dc37c89 2009年09月06日 星期日 21:55 初识ACM最早听说ACM/ICPC ...

  9. 用python实现最长公共子序列算法(找到所有最长公共子串)

    软件安全的一个小实验,正好复习一下LCS的写法. 实现LCS的算法和算法导论上的方式基本一致,都是先建好两个表,一个存储在(i,j)处当前最长公共子序列长度,另一个存储在(i,j)处的回溯方向. 相对 ...

随机推荐

  1. 使用自己的ClassLoader实现热替换

    首先实现一个自己的ClassLoader,该ClassLoader重写findClass方法. 从classpath中加载类资源. 注意,不要重写loadClass方法.  因为在使用自定义的MyCl ...

  2. 如何清理WindowsXp的临时文件

    软件限制策略中的 "路径规则" 不允许的, 是指在 这个路径中的程序都 不准运行! 这就限制了 : 通常电脑中病毒, 都是通过上网感染病毒的 -> 病毒/恶意软件通过 &qu ...

  3. nginx -s reload失败

    在重启nginx时报错误. wangkongming@ThinkPad-T410 ~ $ sudo /usr/sbin/nginx -s reload nginx: [error] invalid P ...

  4. PYTHON学习总结

    升级 python 版本的问题 升级 python 一般会建立软连接,使系统默认的python指向高版本的 python,如: mv /usr/bin/python /usr/bin/python2. ...

  5. css3动画由浅入深总结

    阅读目录 一:过渡动画---Transitions 二:Animations功能 三:translate(tx,ty) 四:scale(x,y) 五:rotate(x): 5.1:skew(x,y): ...

  6. 构建spring+mybatis+redis架构时遇到的小异常

    异常一: Caused by: java.lang.NoSuchMethodError: org.springframework.beans.BeanUtils.instantiateClass(Lj ...

  7. xcode的调试技巧

    转自:http://www.cnblogs.com/daiweilai/p/4421340.html#biyouji 目录 前言逼优鸡知己知彼 百战不殆抽刀断Bug 普通操作 全局断点(Global ...

  8. 2013nanjignB

    B - Poor Warehouse Keeper Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & ...

  9. 【转】(笔记)CANopen协议【CANFestival】移植方法

    一.背景 CAN组网就必须得要应用层协议,原因就在于 * 便于网络管理与控制 * 确认数据的收发 * 发送大于8个字节的数据块(CAN每帧数据传输大小为8字节) * 为不同节点分配不同的报文标识符 * ...

  10. 【定时任务|开机启动】Windows Server 2008/2012 计划任务配置(任务计划程序)每分钟执行BAT

    打开计划任务快捷方式(在 “管理工具”内): C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Administrative Tools\Tas ...