动态规划
来源:互联网 发布:淘宝模特收费 编辑:程序博客网 时间:2024/05/17 23:56
动态规划(DP)是一种解决复杂问题特别是主问题包含重复子问题的常用算法思想。它将待求解问题分解成若干子问题,先求解子问题,然后再从子问题中得到原问题的解。不同于分治法,动态规划的子问题常常不是互相独立的,下一阶段的求解建立在上一阶段的解的基础上进行的。
利用动态规划求解问题的有效性 依赖于问题本身具有的两个重要性质,也就是如果待解决问题具有以下两个性质,就可以考虑使用动态规划求解。
1 最优子结构:问题的最优解包含了其子问题的最优解。
2 重叠子问题:在求解过程中,如使用递归自顶向下求解问题时,每次产生子问题并不总是新的,有的被重复计算多次,故需要将子问题的解保存下来,供以后直接使用。这种思 想又叫“记表备查”,将求解过程中的最优值保存在决策表中。
求斐波那契数列问题。1 2 3 5 8 13..... f(n) = f(n - 1) + f(n - 2) f(1) = 1, f(2) = 2
使用递归如下:
int Fbnaci(int n) { if(n == 1) return 1; if(n == 2) return 2; if(n > 2) return Fbnaci(n - 1) + Fbnaci(n - 2);}上述代码虽然简洁,但是相当费时,因为有着大量重复问题的计算。如计算f(10)需要计算f(9) 和 f(8) 计算f(9)时又需要计算f(8) .使用动态规划的实现如下:
int Fbnaci(int n) { int i,*a; if(n==1) return 1; if(n==2) return 2; if(n>2) { a=(int *)malloc(sizeof(int)*n); a[0]=1; a[1]=2; for(i=2;i<n;i++) a[i]=a[i-1]+a[i-2]; return a[n-1]; }}以上代码虽然比前面递归的代码量大,但是使用数组保存了中间结果,以后调用时不必再计算,直接使用数组值就可以,从而大大减少了运算时间。(空间换时间)
求(LCS)最大公共子序列问题。
给定两个字符串,求它们共同的最长子序列,(不一定连续)。
对于字符串 X = {x1,x2,...,xm}, Y = {y1,y2,...,yn } 求 Z = {z1,z2,....zk } 其中 zi 同时在字符串X和Y中,且顺序保持不变。
如 X = “ABCBDAB” Y="BDCABA " 最长公共子序列为 BCBA 和 BDAB
最优子结构性质:
1 若 x(m) = y(n) 则 z(k) = x(m) = y(n) 且 {Zk-1} 是 {Xm-1} 和 {Yn-1}的最长公共子序列。
2 若 x(m) != y(n) 且 z(k) != x(m) 则 {Zk} 是{Xm-1}和{Yn} 的最长公共子序列
3 若 x(m) != y(n) 且 z(k) != y(n) 则 {Zk} 是{Yn-1}和{Xm} 的最长公共子序列
简单来说,如果X和Y的最后一个元素相同,则最后一个元素肯定在Z中且是最长子序列的最后一个元素。那么Z的长度为{Xm-1} 和 {Yn-1}的最长公共子序列的长度 + 1
否则最长公共子序列的长度为 : max{ length(Xm-1,Yn) , length(Xm,Yn-1)}
用 数组 c[ i ][ j ]记录X[ 0 ~ i ] 与 Y[ 0 ~ j ] 的最长公共子序列的长度 则:
c[i][j] = 0 if i = 0, j = 0;
= c[i-1][j-1] + 1 else if xi = yj
= max{ c[i][j-1] ,c[i-1][j] } else if xi != yj
以 X = “ABCBDAB” Y="BDCABA " 为例,求得矩阵C如下:(参考算法导论)
其中箭头方向表示当前子问题的解(箭尾) 由上一个子问题(箭头)的最优解得来。
如 c[2][1] = c[1][0] +1 得来;表示i= 2 ,j = 1 时 x2 = y1 = ‘B’ ,则当前子问题最长子序列长度 = 上一子问题最长子序列长度 + 1;其余类似。
具体代码如下:
// Length of LCSint LCSLength(int m,int n,const char x[],char y[]){int i,j;for(i = 1; i <= m; i++)//初始第一行c[i][0] = 0;for(j = 1; j <= n; j++)//初始第一列c[0][j] = 0;for(i = 1; i <= m; i++){for(j = 1; j <= n; j++){if(x[i-1] == y[j-1]) //相等{c[i][j] = c[i-1][j-1] + 1;b[i][j] = 1;}else if(c[i-1][j] >= c[i][j-1]){c[i][j] = c[i-1][j];b[i][j] = 2;}else{c[i][j] = c[i][j-1];b[i][j] = 3;}}}return c[m][n];} //根据数组b内容打印x和y的最大公共子序列void LCSprint(int i,int j,char x[]){if(i == 0 || j == 0)return;if(b[i][j] == 1){//printf("%c",x[i-1]);LCSprint(i-1,j-1,x);printf("%c",x[i]);}else if(b[i][j] == 2)LCSprint(i-1,j,x);elseLCSprint(i,j-1,x);}
注意以上代码中字符串下标从1 开始。
数塔问题:
给定数字三角形,计算从顶至底的某一条路径使该路径所经过的数字的总和最大。
使用二维数组存储上述数据
7
3 8
8 1 0
2 7 4 4
逆向思考,从倒数第二层算起,分别计算每一层所有元素可能达到的最大值,从下往上进行,到第一行时就得到路径最大值。
状态转移方程:C[ i ] [ j ] + = max{ C[ i+1] [ j ] , C[ i+1] [ j +1] }
- 动态规划!!!动态规划!!!
- 动态规划
- 动态规划
- 动态规划
- 动态规划
- 动态规划
- 动态规划
- 动态规划
- 动态规划
- 动态规划
- 动态规划
- 动态规划
- 动态规划
- 动态规划
- 动态规划
- 动态规划
- 动态规划
- 动态规划
- 网站用户密码加密
- iOS解决两个静态库的冲突 duplicate symbol
- WebSphere Application Server 动态高速缓存技术教程
- java类的加载以及初始化顺序
- 【小松教你手游开发】【unity实用技能】Unity NGui 利用UIToggle做个分页标签
- 动态规划
- 【iOS开发系列】微信支付
- Spring整合RMI
- Android单元测试
- mysql5.6迁移到mariadb
- android平台led开发之内核硬件驱动层(一)
- delphi EncdDecd.pas单元中Encoding方法出现#$D#$A的解决方法
- cinder创建volume流程简介
- Unity3d陀螺仪看全景图