议题:动态规划(Dynamic Programming)

分析:

  • DP主要用于解决包含重叠子问题(Overlapping Subproblems)的最优化问题,其基本策略是将原问题分解为相似的子问题,通过求解并保存最简单子问题的解,然后逐步合并成为原问题的解,由于需 要查询子问题的解,所以需要一个表格记录子问题的解;DP仅适用于最优子结构问题(Optimal Substructure),也就是局部最优解相当于(或者近似于)全局最优解;

  • 对于原问题而言,当递归地自顶向下对问题进行求解时,每次产生的子问题可能与之前差生的子问题重复(如Fibonacci数列的求解);DP通过自底向上 求解子问题的解并将其保存在一个表格中,当再次遇到相同子问题时就直接通过查表得到其解(分治算法的子问题则是完全独立子空间);使用DP之前需要判定当 前问题是否具有下述三个特性:

    最优子结构:无论之前的状态和决策如何,当前的局部最优解是构成全局最优解的必要条件;

    无后效性:对于某个给定的阶段状态而言,在此之前的所有决策和状态都无法直接影响未来的决策,而只能通过当前的决策和状态影响;

    空间需求度:DP实际上是一种空间换时间的策略,在求解的过程中需要不断存储子问题的解并提供合理的查询方式;

  • DP的四个步骤

    划分阶段:注意划分之后的阶段必须是有序或者可排序的;

    确定状态和状态变量:将划分后的子问题使用不同状态表示,并满足无后效性;

    确定决策并写出状态转移方程:根据相邻两个阶段的状态关系得出转移方程;

    寻找边界条件:给出的转移方程是一个递归式,需要最终确定一个终止条件;

    最长公共子序列的DP解法

  • LCS问题与LIS(Largest Incremental Sub-sequence)问题类似,将原字符串A进行排序之后得到B,则A的LIS就是A和B的LCS。另外也可以直接使用DP;

  • 解法1:Largest Common Sub-string,如果将需求理解为公共子串的字符必须相连,则解法如下:将字符串A的每一个字符依次匹配B的每一个位置,时间复杂度O(MN),M 和N分别为A和B的长度,同样也可以使用DP填表的方式求解。KMP算法也可以求解,时间复杂度为O(M+N);

  • 解法2:Largest Common Sub-Sequence,如果将需求理解为公共子串的字符可以分离,则为经典的LCS问题(也可以理解为求两个集合的顺序交集),则解法如下:动态规划 (DP),动态规划一般应用于具有最优子结构的问题,也就是局部最优解可以决定全局最优解;动态规划的关键点在问题的拆分和状态关系的转移;

  • 给定first[1,m]和second[1,n],求LCS(first[1,m],second[1,n]),

    如果first和
    second的最后一个字符相同,则有first[m]=second[n]=result[k],这样问题化解为给定first[1,m-1]和
    second[1,n-1],求LCS(first[1,m-1],second[1,n-1]),原问题转化为
    LCS(first[1,m],second[1,n])= LCS(first[1,m-1],second[1,n-1]) +1

    如果first和second的最后一个字符不相同,则问题化解为result[1,k]= max{LCS(first[1,m-1],second[1,n]), LCS(first[1,m],second[1,n-1])

样例:

 /**
* 利用动态规划,使用簿记matrix的方法记录小子问题,然后重复利用
* 小子问题解决合成问题,最终解决整个问题。
* 在first和second组成的二维表中,一共有三种状态转移方式:
* 如果first[m]=second[n],则跳到first[m-1]和second[n-1]
* 如果first[m]!=second[n],则跳到first[m-1]和second[n],
* first[m]和second[n-1]的LCS中较大的一个
* 需要设定初始状态为0
* */
void lcs2(char *first, int lfirst, char *second, int lsecond) {
int *dir=new int[lfirst*lsecond];
int *dis=new int[lfirst*lsecond];
/**
* 保留first和second的第一个字符,将其dis设置为0,便于实现簿记
* dir矩阵中:0表示up-left移动;1表示left移动;2表示up移动
* */
for(int i=;i<lfirst;i++)
dis[i]=;
for(int i=;i<lsecond;i++)
dis[i*lfirst]=; for(int j=;j<lsecond;j++) {
for(int i=;i<lfirst;i++) {
if(first[i]==second[j]) {
/**
* 如果当前字符相等,则说明[i,j]长度的LCS为
* [i-1,j-1]长度的LCS 加上1;
* up-left移动
* */
dis[i+j*lfirst]=
dis[(i-)+(j-)*lfirst]+;
dir[i+j*lfirst]=;
} else if(dis[i+(j-)*lfirst] >
dis[(i-)+j*lfirst]) {
/**
* 如果当前字符不等,并且[i,j-1]长度的LCS大于
* [i-1,j]长度的LCS,则当前[i,j]长度的LCS等于
* [i,j-1]产度的LCS
* up移动
* */
dis[i+j*lfirst]=
dis[i+(j-)*lfirst];
dir[i+j*lfirst]=;
} else {
/**
* 如果当前字符不等,并且[i-1,j]长度的LCS大于
* [i,j-1]长度的LCS,则当前[i,j]长度的LCS等于
* [i-1,j]产度的LCS
* left移动
* */
dis[i+j*lfirst]=
dis[(i-)+j*lfirst];
dir[i+j*lfirst]=;
}
}
} showLCS(first, dir, lfirst-, lsecond-, lfirst); delete [] dir;
delete [] dis;
}

参考连接:
http://blog.csdn.net/v_july_v/article/details/6695482
http://en.wikipedia.org/wiki/Dynamic_programming
http://blog.csdn.net/sharpdew/article/details/763180

最新文章

  1. 标准产品+定制开发:专注打造企业OA、智慧政务云平台——山东森普软件,交付率最高的技术型软件公司
  2. 9月27日Bootstrap
  3. jQuery新的事件绑定机制on()
  4. HTML5程序设计--SVG
  5. 【温故知新】C#委托delegate
  6. indexof()方法
  7. Installing — pylibmc 1.2.3 documentation
  8. IScroll5+在ios、android点击(click)事件不兼容解决方法
  9. sass 安装和使用
  10. Java线程经典面试题
  11. js原生写的微博留言板有angularjs效果
  12. SPI通讯协议
  13. Linux--慕课学习
  14. 用Git将本地项目推送到github
  15. 【新手向】使用nodejs抓取百度贴吧内容
  16. 深入浅出JAVA线程池使用原理2
  17. WebSocket 启用压缩
  18. blob下载出现多余乱码内容
  19. manifest.xml
  20. MySQL 如何更新某个字段的值为原来的值加1

热门文章

  1. 【183】VMware + CentOS 安装教程等
  2. 解决axios IE11 Promise对象未定义
  3. jetbrains软件使用
  4. poj 3130 How I Mathematician Wonder What You Are! 【半平面交】
  5. 【插件开发】—— 4 SWT编程须知
  6. Java SE 第二篇
  7. 第四章 朴素贝叶斯法(naive_Bayes)
  8. SQL 初级教程学习(三)
  9. 题解报告:hdu 1257 最少拦截系统(贪心)
  10. shell 调试 2例