动态规划

动态规划

  • 数字三角形

    用递归实现,复杂度为2^n

    # include<iostream>
    //max函数在algorithm头文件里
    # include<algorithm>
    using namespace std;
    
    #define MAX 101;
    int N;
    int D[MAX][MAX];
    
    int maxSum(int i,int j){
        if(i == N) return D[i][j];
        else{
            return max(maxSum(i+1,j),maxSum(i+1,j+1])+D[i][j];
        }
    }
    int main(){
        cin >> N;
        for(int i = 0;i<N;i++){
            for(int j = 0;j<=i;j++){
                cin >> D[i][j];
            }
        }
        cout << maxSum(0,0);
    }
    
  • 使用动态规划来做

    #include<iostream>
    #include<algorithm>
    #define MAX 101
    using namespace std;
    int N;
    int D[MAX][MAX];
    //一个记录中间运算结果的数组
    int maxSum[MAX][MAX];
    
    int MaxSum(int i,int j){
        //如果已经算过一次,无需再次计算,避免了重复计算降低复杂度
        if(maxSum[i][j] != -1) return maxSum[i][j];
        //如果为最后一行,D[i][j]的值就是maxSum[i][j]的值
        if(i==N) maxSum[i][j] = D[i][j];
        else{
            maxSum[i][j] = max(MaxSum(i+1,j),MaxSum(i+1,j+1))+D[i][j];
        }
        return maxSum[i][j];
    }
    int main(){
        cin >> N;
        for(int i = 0;i<N;i++){
            for(int j = 0;j<= i;j++){
                cin >> D[i][j];
                //给存储中间数据的数组赋一个不可能的初值
                maxSum[i][j] = -1;
            }
        }
        cout << MaxSum(0,0);
    }
    
    • 因为递归要用到函数调用,我们可以直接用递推做,不用调用函数,提高效率

    • 而且递归可能存在递归深度太大,堆栈不够用的情况

#include<iostream>
#include<algorithm>
#define MAX 100
using namespace std;

int N;
int D[MAX][MAX];
int maxSum[MAX][MAX];

int main(){
    cin >> N;
    for(int i = 0;i<N;i++){
        for(int j = 0;j<=i;j++){
            cin >> D[i][j];
        }
    }
    //边界值——最后一行是确定的
    for(int j = 0;j<N;j++){
        maxSum[N][j] == D[N][j];
    }
    //往上递推
    for(int i = n-1;i>=0;i--){
        for(int j = 0;j<=i;j++){
            maxSum[i][j] = max(maxSum[i+1][j],maxSum[i+1][j+1])+D[i][j];
        }
    }
    cout << maxSum[0][0];
}
  • 进一步,可以进行空间优化,使用以为数组存储maxSum,因为里面的数是滚动更新的;

  • 这也体现了递推的一个优势——有时候可以使用滚动数组

#include <iostream>
#include <algorithm>
#define MAX 100
using namespace std;
int D[MAX][MAX];
int n;
int main(){
    cin >> n;
    for(int i = 0;i<n;i++){
        for(int j = 0;j<=i;j++){
            cin >> D[i][j];
        }
    }
    int * sumMax;
    //建立一个指针指向D[n],把递推的过程变成更新D[n]中的数
    sumMax = D[n];
    for(int i = n-1;i>=0;i--){
        for(int j = 0;j<=i;j++){
            sumMax[j] = max(sumMax[j],sumMax[j+1]) + D[i][j];
        }
    }
    cout << sumMax[0];
}
  • 最长上升子序列问题

    #include <iostream>
    #include <algorithm>
    #define MAX 1000
    using namespace std;
    int a[MAX];
    //建立 一个数组来存放每一个状态
    int maxLen[MAX];
    int n;
    int main(){
       cin >> n;
       for(int i = 0;i<n;i++){
           cin >> a[i];
           maxLen[i] = 1;
       }
       for(int i = 1;i<n;i++){
           for(int j = 0;j<i;j++){
               //maxLen[]是不断更新的,max函数控制是否要更新maxLen
               if(a[i]>a[j]) maxLen[i] = max(maxLen[i],maxLen[j]+1);
           }
       }
        //输出maxLen[](容器)中最大的一个,第一个参数为起始,左闭右开;在头文件algorithm中
        cout << * max_element(maxLen,maxLen+n);
    }
    
    • 最长子串问题
#include<iostream>
#include<cstring>
#include<algorithm>
#define MAX 1000
using namespace std;

char str1[MAX];
char str2[MAX];
//有两个
int maxLen[MAX][MAX];
int main(){
    while (cin >> str1 >> str2)
    {
        int lenth1 = strlen(str1);
        int lenth2 = strlen(str2);
        int nTmp;
        int i,j;
        //先确定边界状态
        for(i = 0;i < lenth1;i++){
            maxLen[i][0] = 0;
        }
        for(j = 0;j < lenth2;j++){
            maxLen[0][j] = 0;
        }
        //递推式,这里是难点
        for(int i = 1;i<lenth1;i++){
            for(int j = 1;j<lenth2;j++){
                //这里如果不用i-1第一个字母相同不会记录
                if(str1[i-1] == str2[j-1]){
                    maxLen[i][j] = maxLen[i-1][j-1] +1;
                }else{
                //证明,maxLen[i][j]不小于其中的任何一个也不大于其中的任何一个
                    maxLen[i][j] = max(maxLen[i-1][j],maxLen[i][j-1]);
                }
            }
        }
           cout << maxLen[lenth1-1][lenth2-1] << endl;
          
    }
    return 0;
}
  • 动态规划问题最难的地方是

    设计状态,找到状态转移的递推关系式

    设计状态的原则:

    是原问题子问题的解

    具有最有子结构(原问题的最优解所包含的子问题,解也是最优的)

    无后效性(只跟当前状态有关,而与怎么抵达这个状态无关)

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容