算法小结--动态规划(二)

来源:互联网 发布:.js是什么文件 编辑:程序博客网 时间:2024/06/15 08:36
通过实例,我们已经了解到动态规划的求解方法,DP算法采用分治算法的思想,将原问题分为若干个子问题,然后分别求解各个子问题,最后将子问题组合起来得到原问题的解。动态规划的高明之处是不会重复求解某些出现过的子问题(01背包问题中,通过记忆化数组避免重复求解),即重叠子问题。

动态规划算法常用来求解最优化问题,常见的步骤如下:

  1. 分析问题,找出最优解结构
  2. 递归定义一个最优解的值
  3. 从最简单的问题入手,计算出最优解的值
  4. 根据计算最优解的值的信息,构造一个最优解

通过例题来加深理解DP的算法思想

经典例题:最长公共子序列问题
一个字符串的子序列,是指从该字符串中去掉任意多个字符后剩下的字符在不改变顺序的情况下组成的新字符串。求两个字符串的最长公共子序列。


一般的递归求解方法:

#include <iostream>#include<string>using namespace std;int mymax(int a,int b){    return a>b?a:b;}int fuc(string s1,string s2){    if(s1.length()==0 || s2.length()==0) return 0;    if(s1.at(0)==s2.at(0)) return 1+fuc(s1.substr(1),s2.substr(1));    else return mymax( fuc(s1,s2.substr(1)),fuc(s1.substr(1),s2) );}int main(){    int res = fuc("sfwsw","wsdfs");    cout << res << endl;    return 0;}
递归算法对于求解规模较大的数据显然不够用的,所以需要对算法进行优化

记忆化数组法:

#include <iostream>#include <string>#include <string.h>using namespace std;int mem[20][20]; //保存计算过的字串的最大公共字串,避免重复计算int mymax(int a,int b){    return a>b?a:b;}int fuc(string s1,string s2,int m,int n){    int rec;    if(mem[m][n]!=-1) return mem[m][n];    if(s1.length()==0 || s2.length()==0)  return 0;    if(s1.at(0)==s2.at(0)) rec = 1+fuc( s1.substr(1),s2.substr(1),m+1,n+1 );    else  rec = mymax( fuc(s1,s2.substr(1),m,n+1),fuc(s1.substr(1),s2,m+1,n) );    mem[m][n] = rec;    return rec;}int main(){    memset(mem,-1,sizeof(mem));    int res = fuc("afasdf","sdfsaf",0,0);    cout << res << endl;    return 0;}

本题也可以使用递推式求解,但是不如记忆化数组法比较容易就能实现。


小结及感悟:想要熟练掌握动态规划思想也没有什么捷径,无非是勤加练习。看了许多动态规划的例题,感觉仔细分析理解后,遇到新的问题,又不知道怎么构造出动态规划的基本框架,尤其是递归方程比较难以得出。分析问题的最优子结构是难点和重点。

0 0
原创粉丝点击