动态规划

我就是我 2022-12-01 11:51 132阅读 0赞

一:概念:
和分冶法相似,不同之处在于前者是把问题划分为互不相交的子问题,而动态规划会出现子问题重叠的情况。通常用来求解最优化问题。。
基本步骤:
①:刻画一个最优解的结构特征。
②:递归的定义最优解的值。
③:计算最优解的值,通常采用自底向上的方法。
④:利用计算出的信息构造最优解。
两个基本特征:
①:最优子结构:最优解由相关子问题的最优解构成。(子问题之间互不相关)
②:重叠子问题:问题的递归算法会反复求解相同的子问题,而不是一直生成新的子问题。
二:例子:
1.钢条切割问题:一根长度为n的钢条,i长度的出售价格为p[i],求解切割之后(可多次切割)的钢条最多卖多少钱。

*最优解特征:n被切割为j和k,还需要继续分析j和k如何切割。
*重叠子问题:在小段为1之前,总是会求解一些相同长度的切割问题。
*状态转移方程:q[n]=max(p[i]+q[n-i]);

算法(java):
①:自顶向下(分冶法)(不可直接运行)

  1. public class Divide{
  2. int p[]=new int[0,1,5,8,9,10,17,17,20,24,30];//i长度的钢条的价格表(可用哈希表)
  3. main()
  4. {
  5. syso"请输入要切割的钢条长度n");
  6. Scanner scanner=new Scanner(System.in);
  7. int n=scanner.nextint();
  8. scanner.close(); //获取钢条的长度
  9. int q=0;
  10. q=Divide(n,q); //调用自顶向下的算法
  11. syso(q);
  12. }
  13. public int Divide(int n,int q)
  14. {
  15. for(int i=0;i<n;i++)
  16. {
  17. q=Math.max(q,Divide(n-i,q))//状态转移方程
  18. }
  19. return q;
  20. }
  21. /*因为采用的是自顶向下的算法,会重复计算多个重叠子问题,可以一个数组暂时保存已经求解过的子问题,即动态规划
  22. */
  23. }

②自底向上(动态规划)(不可直接运行):

  1. //不会重复计算子问题。
  2. public class Divide{
  3. int p[]=new int[0,1,5,8,9,10,17,17,20,24,30];//i长度的钢条的价格表(可用哈希表)
  4. main()
  5. {
  6. syso"请输入要切割的钢条长度n");
  7. Scanner scanner=new Scanner(System.in);
  8. int n=scanner.nextint();
  9. scanner.close(); //获取钢条的长度
  10. int q[]=new int[n];//分别对应i长度的钢条的最佳切割结果价格
  11. q[0]=0;
  12. for(int i=0;i<n;i++)
  13. {
  14. int q=0;
  15. for(int j=0;j<i;j++)
  16. {
  17. q=Math.max(q,q[j]+q[i-j]);//状态转移方程
  18. }
  19. q[j]=q;//更新最优解数组
  20. }
  21. syso(q[n]);
  22. return q[n];//返回要求的值
  23. }

2.最长公共子序列问题:
求出两个序列中的最长公共子序列,不要求连续,例如:S1=ACCGT,
S2=ACCT,则输出结果X=ACCT。

*最优子结构:S1的前n1个字符和S2的前n2个字符的最长公共子序列将是S1和S2的整个最长公共子序列的前缀。S1的前n1个字符或者S2的前n2个字符也可看做是序列,短序列的解是长序列的解,即子问题的解是大问题的解,所以满足最优子结构。
**重叠子问题:计算比较长的序列的最长公共子序列会多次重复计算较短序列的最长公共子序列
*状态转移方程:C[I,j]表示S1的0到i个元素和S2的0到j个元素的最长公共子序列。
C[I,j]=
① 0 (i=0&&j==0)
② C[i-1,j-1]+1 (S1i=S2j)
③Max{C[i-1,j],C[j-1,i]} (S1i!=S2j)

算法思想:
用C[][]来维护最长公共子序列的长度
用b[][]来保存序列。
算法代码(java)(动态规划)(不可直接运行):

  1. LCS-Length(String S1,String S2)
  2. {
  3. m=S1.length();
  4. n=S2.length();
  5. int C[][]=new int[m][n];//长度数组
  6. int b[][]=new int[m][n];//前驱序列数组
  7. for(int i=0;i<m;i++)//初始化第一列
  8. {
  9. C[i][0]=0;
  10. }
  11. for(int i=0;i<n;i++)//初始化第一行
  12. {
  13. C[0][i]=0;
  14. }
  15. for(int i=0;i<m;i++) //根据状态转移方程循环
  16. {
  17. for(int i=0;i<n;i++)
  18. {
  19. if(S1[i]==S2[j])
  20. {
  21. C[i][j]=C[i-1][j-1]+1;
  22. b[i][j]=3; //3代表前序是左上方的序列
  23. }
  24. else
  25. {
  26. if(C[i-1][j]>=C[i][j-1])
  27. {
  28. C[i][j]=C[i-1][j];
  29. b[i][j]=2; //代表前驱是上方的序列
  30. }
  31. else
  32. {
  33. C[i][j]=C[i][j-1];
  34. b[i][j]=1;
  35. }
  36. }
  37. }
  38. }
  39. }
  40. LCS-print(String S1,String S2,int b[][],int i,int j)//输出最长序列
  41. {
  42. if(b[i][j]==3)//b[i][j]=3说明S1i是等烟雨S2j的,是最长公共子序列的一个元素,输出即可
  43. {
  44. syso(S1i);
  45. LCS-print(S1, S2, b[][], i-1,j-1);
  46. }
  47. else if(b[i][j]==2)//等于2的情况对应最长公共子序列是S1(i-1)和S2j的最长公共子序列
  48. {
  49. LCS-print(S1, S2, b[][], i-1,j);
  50. }
  51. else //等于1的情况对应最长公共子序列是S1i和S2(j-1)的最长公共子序列
  52. {
  53. LCS-print(S1, S2, b[][], i,j-1);
  54. }
  55. }

发表评论

表情:
评论列表 (有 0 条评论,132人围观)

还没有评论,来说两句吧...

相关阅读

    相关 动态规划

    一:概念: 和分冶法相似,不同之处在于前者是把问题划分为互不相交的子问题,而动态规划会出现子问题重叠的情况。通常用来求解最优化问题。。 基本步骤: ①:刻画一个最优

    相关 动态规划

    -------------------- 动态规划的设计思想 动态规划(DP)\[1\]通过分解成子问题解决了给定复杂的问题,并存储子问题的结果,以避免再次计算相同的结

    相关 动态规划

    1. 首先,动态规划不是一个特定的算法,它代表的是一种思想,一种手段 2. 动态规划方法往往用于求解“最优化问题”,能用动态规划求解的问题的前提是问题具有“最优子结构性质”

    相关 动态规划

    首先是概念:动态规划就是将原问题划分为简单的几个小问题(有点类似与分治法?但是分治法中的各个小问题是相互独立的,彼此之间不会产生影响,但是动态规划中所得的值和前面相关,当前的解

    相关 动态规划

    > 给定两个字符串A和B,返回两个字符串的最长公共子序列的长度。例如,A=”1A2C3D4B56”,B=”B1D23CA45B6A”,”123456”或者”12C4B6”都是最

    相关 动态规划

    基本思想:     动态规划算法与分治法类似,其基本思想也是将待求解问题分解成若干个子问题,先求解子问题,然后从这些子问题的解得到原问题的解。 区别:     与

    相关 动态规划

    等我有时间了,一定要把《算法导论》啃完,这本书的印刷质量实在太好了,就是烧脑子,滑稽。 适合应用动态规划求解的最优化问题应该具备两个要素: 最优子结构:一个问题的最优解包含

    相关 动态规划

     1.题目:最长递增子序列(Longest Increasing Subsequence) 问题描述: > 给定长度为N的数组A,计算A的最长单调递增的子序列(不一定连续)