动态规划法

为什么不用递归:
因为递归进行计算的时候会产生较多的重复计算,例如求斐波那契数列fib(8),
在这里插入图片描述
中间的fib(5),fib(4),fib(3),fib(2)等重复计算了好多次,导致不必要的计算,当然可以用一个数组来储存计算过的值,这样也是一种优化思路。

动态规划的主要的思路是先建模,建立一个金字塔模型用于分析问题,确定状态。然后从下往上计算,用一个数组储存计算过的底层的最优解,最后数组最后一个值就是总问题的最优解。

例题1:
找出两个字符串的公共子序列。
思路:首先需要一个二维数组用来存储底层的状态值,每次计算是否相同的时候还应该考虑前一个已经计算的值,来决定这个值到底是什么状态。
代码:

#include<iostream>
#include<string>

using namespace std;

char s1[4] = "asd";

char s2[4] = "ase";
int Max_str(int length1, int length2){
    int exit_[length1+1][length2+2];
    for(int i = 0; i<=length1; i++){
        exit_[i][0] = 0;
    }
    for(int j = 0; j<=length2; j++){
        exit_[0][j] = 0;
    };
    for(int i = 1;i<=length1;i++){
        
        for(int j = 1;j<=length2; j++){
            
            if(s1[i-1] == s2[j-1]){
                exit_[i][j] = exit_[i-1][j-1]+1;
            }
            else{
                int A = exit_[i-1][j];
                int B = exit_[i][j-1];
                exit_[i][j] = A>B?A:B;
            }
        }
    }
    return exit_[length1][length2];
}
int main(){
    cout<<sizeof(s1)<<endl;
    cout<<sizeof(s2)<<endl;
    cout<<Max_str(sizeof(s1),sizeof(s2))<<endl;
    return 0;
}

例题二:

数字三角形(POJ1163)
在这里插入图片描述
在上面的数字三角形中寻找一条从顶部到底边的路径,使得路径上所经过的数字之和最大。路径上的每一步都只能往左下或 右下走。只需要求出这个最大和即可,不必给出具体路径。 三角形的行数大于1小于等于100,数字为 0 - 99。

递归思路:
三角形用一份二维矩阵存储,不断往下面递归,返回两个相加和较大的一个。
代码:

#include<iostream>

using namespace std;

int temp[5][5];
int D[100][100];

int Maxpath(int i,int j){
    if(i == 4 ){
        return D[i][j];
    }
    else{
        int A = Maxpath(i+1,j);
        int B = Maxpath(i+1,j+1);
        return (A>B?A:B)+D[i][j];
    }
    // return temp[i][j];
    
};
int main(){
    int temp1[] = {7,3,8,8,1,0,2,7,4,4,4,5,2,6,5};
    int cout = 0;
   
    for(int i = 0; i<5; ++i){
        for(int j = 0;j<=i ; ++j){
            D[i][j] = temp1[cout++];
        }
    }
    std::cout << Maxpath(0, 0) << std::endl;
}

这边用递归在解决子问题的时候产生了多个不必要的重复计算,所以效率不是太高。

动态规划思路:
分析这种问题一般是从上到下的建模分析问题,从下到上的解决问题。现在是从二维矩阵的最下面一层开始进行向上运算,我们可以用原来的二维矩阵储存已经计算过的值。
代码:

#include<iostream>

using namespace std;

int temp[5][5];
int D[100][100];

int main(){
    int temp1[] = {7,3,8,8,1,0,2,7,4,4,4,5,2,6,5};
    int cout = 0;
   
    for(int i = 0; i<5; ++i){
        for(int j = 0;j<=i ; ++j){
            D[i][j] = temp1[cout++];
        }
    }
    int A,B;
    for(int i = 4; i>=0;i--){
        for(int j = i; j>=0; j--){
            if(i == 4){
                
            }
            else{
                A = D[i+1][j]+D[i][j];
                B = D[i+1][j+1]+D[i][j];
                D[i][j] = A>B?A:B;
            }
        }
    }
    std::cout << D[0][0] << std::endl;
    return 0;
}

最长公共子序列问题:
求两个字符串的最长公共子序列(最长公共子序列可以是不连续的,最长公共子串是连续的)。
思路分析:这是一道经典的动态规划的题,我们从两个字符串的最后面进行分析,如果两个字符串的最后一个字母是相同的,那么这个字母就是公共子序列里面的最后一份值,如果最后两个不相同,那么就是比较去掉最后一个字母的字符串A和另外一个字符串B的比较公共子序列的值,或者是去掉最后一个字符的字符串B和另外一个完整的字符串A比较公共子序列。这就是主体思路。
动态规划法实现思路:找个一二维数组从两个字符串的开头进行遍历,若两个字符串相同,则数组储存值在前一个相同的基础上面加一,否则就储存前一个不同值里面的最大值(也就是数组位置里面的上面和左面的最大值)。最后返回数组右下角储存的值就是最长公共子序列的长度。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值