• 算法1:动态规划


           动态规划的基本思想是:将求解的问题分解成若干个子问题,先求解子问题,然后再从这些子问题的解得到原问题的解。与分治法的区别是,适合用动态规划解决的问题,经分解得到的子问题往往不是相互独立的。动态规划将问题分解成子问题,但是子问题不相互独立,而是彼此依赖,相互提供帮助,很好的利用了子问题的结构信息。

    动态规划的步骤是:

    1.找出最优解的特征,并刻画其结构特征;

    2.递归地定义最优值;

    3.以自底向上的方式计算出最优值;

    4.根据计算最优值的时得到的信息,构造最优解。

    动态规划算法的有效性依赖于两个最重要的性质:最优子结构性质和重叠子问题性质。

    栗子1,矩阵连乘问题。

     1 //动态规划——矩阵连乘问题
     2 #include<iostream>
     3 #include<cstring> 
     4 
     5 using namespace std;
     6 int p[7]={30,35,15,5,10,20,25};//6个矩阵
     7 int m[6][6];//存放计算量的矩阵
     8 int s[6][6];//存放分割点的矩阵
     9 
    10 void matrixChain()//第三步:计算最优值(前面两步没法再代码中体现,是构思的过程)
    11                   //生成断点矩阵的函数,计算出最优值,返回s矩阵
    12 {
    13     int length=6;
    14     memset(m,0,sizeof(m));
    15     memset(s,0,sizeof(s));
    16     for(int r=2;r<=length;r++)//r表示的是计算的范围,开始只计算两个矩阵的计算量,然后依次计算3个,4个一直到目标的6个
    17                               //这是动态规划自底向上的体现,从最小的单位开始计算
    18     {
    19         for(int i=1;i<=length-r+1;i++)//i,j分别表示当前所计算的范围
    20         {
    21             int j=i+r-1;
    22             m[i][j]=m[i][i]+m[i+1][j]+p[i]*p[i-1]*p[j];//因为后面要求最优值,所以这里其实是随便求一个值
    23             s[i][j]=i;
    24             for(int k=i+1;k<j;k++)//范围内优化,找到最小的值
    25             {
    26                 int temp=m[i][k]+m[k+1][j]+p[i-1]*p[k]*p[j];
    27                 if(temp<m[i][j])
    28                 {
    29                     m[i][j]=temp;
    30                     s[i][j]=k;
    31                 }
    32             }
    33         }
    34     }
    35 }
    36 void TraceBack(int i,int j)//第4步:构造最优解。输入s矩阵和想要求解的范围,输出最佳的括号方案
    37 {
    38     if(i==j)
    39     {
    40         cout<<"M"<<"["<<i<<"]";
    41         return;
    42     }
    43     cout<<"(";
    44     TraceBack(i,s[i][j]);
    45     TraceBack(s[i][j]+1,j);
    46     cout<<")";
    47 }
    48 int main()
    49 {
    50     matrixChain();
    51     TraceBack(1,6);
    52     cout<<m[1][6]<<endl;
    53     return 0;
    54 }

     栗子2:最长公共子序列

     1 //动态规划-最长公共子序列
     2 #include<iostream>
     3 using namespace std;
     4 char x[8]={'Z','A','B','C','B','D','A','B'};//函数中根本不会计算x[0]和y[0],这两个位置的字母只是为了占坑用
     5 char y[7]={'Z','B','D','C','A','B','A'};
     6 int c[8][7]={0};//子序列的长度
     7 int b[8][7]={0};//子序列以哪种方式可以找到它最长子序列。递归方式
     8 //计算最优值
     9 void lcsLength()
    10 {
    11     int m=7;//第一个序列的长度
    12     int n=6;//第二个序列的长度
    13     for(int i=1;i<=m;i++)
    14     {
    15         for(int j=1;j<=n;j++)
    16         {
    17             if(x[i]==y[j])
    18             {
    19                 c[i][j]=c[i-1][j-1]+1;
    20                 b[i][j]=1;
    21             }
    22             else
    23             {
    24                 if(c[i-1][j]>c[i][j-1])
    25                 {
    26                     c[i][j]=c[i-1][j];
    27                     b[i][j]=2;
    28                 }
    29                 else
    30                 {
    31                     c[i][j]=c[i][j-1];
    32                     b[i][j]=3;
    33                 }
    34                 
    35             }
    36             
    37         }
    38     }
    39 }
    40 //构造最优解
    41 void lcs(int i,int j)//输出子序列和其长度
    42 {
    43     if(i==0||j==0)
    44     return;
    45     if(b[i][j]==1)
    46     {
    47         lcs(i-1,j-1);
    48         cout<<x[i];
    49     }
    50     else
    51     {
    52         if(b[i][j]==2)
    53         {
    54             lcs(i-1,j);
    55         }
    56         else
    57         {
    58             lcs(i,j-1);
    59         }
    60         
    61     }
    62     
    63  
    64 
    65 }
    66 int main()
    67 {
    68     lcsLength();
    69     lcs(7,6);
    70     cout<<c[7][6]<<endl;//子序列的最大长度
    71     return 0;
    72 }

     在牛客上提交的版本,牛客只需要输出最长公共子序列的长度

     1 //动态规划-最长公共子序列
     2 #include<iostream>
     3 using namespace std;
     4 void lcsLength(char x[],char y[],int m,int n)
     5 {
     6     int c[m+1][n+1];//子序列的长度
     7     for(int i=0;i<m+1;i++)
     8     {
     9         for(int j=0;j<n+1;j++)
    10             c[i][j]=0;
    11     }
    12     int b[m+1][n+1];//子序列以哪种方式可以找到它最长子序列。递归方式
    13     for(int i=0;i<m+1;i++)
    14     {
    15         for(int j=0;j<n+1;j++)
    16             b[i][j]=0;
    17     }
    18     for(int i=1;i<=m;i++)
    19     {
    20         for(int j=1;j<=n;j++)
    21         {
    22             if(x[i]==y[j])
    23             {
    24                 c[i][j]=c[i-1][j-1]+1;
    25                 b[i][j]=1;
    26             }
    27             else
    28             {
    29                 if(c[i-1][j]>c[i][j-1])
    30                 {
    31                     c[i][j]=c[i-1][j];
    32                     b[i][j]=2;
    33                 }
    34                 else
    35                 {
    36                     c[i][j]=c[i][j-1];
    37                     b[i][j]=3;
    38                 }
    39                  
    40             }
    41              
    42         }
    43     }
    44     cout<<c[m][n]<<endl;
    45 }
    46 void lcs()
    47 {
    48     char a[1024];
    49     a[0]='Z';
    50     char b[1024];
    51     b[0]='Z';
    52     string str1;
    53      string str2;
    54     while(cin>>str1>>str2)
    55     {
    56         for(int i=0;i<str1.size();i++)
    57             a[i+1]=str1[i];
    58         for(int i=0;i<str2.size();i++)
    59             b[i+1]=str2[i];
    60         lcsLength(a,b,str1.size(),str2.size());
    61     }
    62 }
    63 int main()
    64 {
    65     lcs();
    66     return 0;
    67 }
  • 相关阅读:
    sqlserver判断字段是否存在,表是否存在
    sqlserver数据库数据字典生成器
    C#断点续传下载文件
    c# 泛型new T
    html显示xml内容
    程序设计语言诞生——程序设计语言的发展历史
    atan2(x,y) pow(x,y)
    name phone email 正则表达式
    第八周
    第六周
  • 原文地址:https://www.cnblogs.com/neverland0718/p/11348868.html
Copyright © 2020-2023  润新知