动态规划①------从小白开始学习动态规划!

        在班上某位acmer的推荐下,入门了以下网站:https://oi-wiki.org/(听说是由某位高中生大佬开发的!佩服~)

        在里面有很多关于动态规划的知识点,以及各种不同动态规划类型的题目。

        就我而言,我觉得动态规划其实就是把一些解题要用到的数据保存下来,避免重复计算。

        至于动态规划的需要满足的三个条件:①最优子结构,②无后效性,③子问题重叠,大家就自行在里面观看吧,毕竟既然写在这里的题目,那包可以用动态规划来解决的~

        其次,作为小白,我觉得动态规划的题目一般是先确认状态(即dp数组的含义),然后就是状态转移方程,有了这两个东西,基本上题目已经完成一大半了,剩下的就是代码的实现了。

        话不多说,先从其引入的第一题开始:数字三角形

        之前老师也在课堂上提到过这个题目,也简单讲解了一下思路,但过了几周也是全给我忘了。所以基本上是重新开始看这题目,不难也适合新手学习。首先看一下题目:

        正常人看上去的第一眼就会想到自顶向下求解(包括我),但是这样暴力求解的话时间复杂度极高。而且在每一层的最优解并不一定是最底层的最优解,例如简单的7->3和7->8,虽然看上去7->8目前的值最大,但是仔细一看第三层会发现7->3->8会更好。所以我们要回到动态规划的本质,即如何划分子问题上来。

        这个问题是要求一条路径到最底层(设为r)最大,那么反过来想如果知道了r层的所有数值,那么r-1层的数值全部遍历一遍,即加上左下角和右下角的值取最大,那么这样一层一层往上递进下去,到了第一层其实已经包含了所有路径中最大值了。即状态转移方程为:

        

dp[i][j]=max(dp[i+1][j]+w[i][j],dp[i+1][j+1]+w[i][j]);
//其中dp[i][j]表示第i行第j列的数到底层数值的最大值

        至于为什么不能正着遍历,却要反过来遍历,跟动态规划的最优子结构有关,即求出的每一层的dp的最优解必须是最后结果的最优解,而正着遍历的话显然,每一层的最优解有可能只是局部最优解。

        最后贴出代码:

#include<iostream>
using namespace std;

const int N =1001;
int w[N][N],dp[N][N];

int main(){
    int r;
    cin>>r;
    for(int i=1;i<=r;i++){
        for(int j=1;j<=i;j++){
        cin>>w[i][j];
    }    
    }
    
    for(int i =1;i<=r;i++){dp[r][i]=w[r][i];}

    for(int i =r-1;i>0;i--){
    for(int j =1;j<=i;j++){
        dp[i][j]=max(dp[i+1][j]+w[i][j],dp[i+1][j+1]+w[i][j]);
    }
    }
    cout<<dp[1][1]<<endl;
    return 0;
}

  • 6
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值