基础动态规划第一课

今天信息学潇湘馆第一次开张,馆主也挺高兴的,馆主其实也是只蒟蒻,写博客只是为了与大家分享收获并反思总结,以后还望大家多关注我信息学潇湘馆哦,好了,闲话少说,进入正题!

动态规划这一章节对于很多入门的OIer有点苦恼,但是熟练后就会比较轻松,当然不是一节课能讲清楚地,想博主当年可是花了老大的尽呢,动态规划(dp)是一种拆分问题以递推或分治的思想解决到当前的最优解,通常用来求最优、最大或最小等等,那为什么要用动态规划呢?因为贪心虽然每一步都是最优的,但最后总的不一定是最优的(马上见题就知道了),相反也就是说动态规划不一定每一步都是最优的,但是最后总的是最优的,现在我们就来看一道动态规划最经典的题,都被用臭了

三角形最佳路径问题
从三角形的顶部到底部有很多条不同的路径。对于每条路径,把路径上面的数加起来可以得到一个和,和最大的路径称为最佳路径。你的任务就是求出最佳路径上的数字之和。
注意:路径上的每一步只能从一个数走到下一层上和它最近的下边(正下方)的数或者右边(右下方)的数。
如下所示的由正整数数字构成的三角形:
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
从三角形的顶部到底部有很多条不同的路径。对于每条路径,把路径上面的数加起来可以得到一个和,和最大的路径称为最佳路径。你的任务就是求出最佳路径上的数字之和。
注意:路径上的每一步只能从一个数走到下一层上和它最近的下边(正下方)的数或者右边(右下方)的数。
输入
第一行为三角形高度100>=h>=1,同时也是最底层边的数字的数目。
从第二行开始,每行为三角形相应行的数字,中间用空格分隔。
输出
最佳路径的长度数值。
样例输入
5
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5
样例输出
30

这道题我们分析得出就是求从第一层走到第n层每次只能向正下或正下右边的一个走,求走过的路径最大数字和,这道题如果按贪心的话就是从(1,1)->(2,2)->(3,2)->(4,2)->(5,2),总和只有28,并不是最大的,可见这种题目不能用贪心。

这道题用动态规划有两种方法,一种就是从上面(1,1)走到第n层,再把第n层“打擂台”扫一遍,选最大的,还有一种就是从最后一层向上走,走到(1,1),然后这个第一层f(1,1)存储的就是最优的,两种代码都会给出

第一种

#include <bits/stdc++.h>
using namespace std;
int n,a[105][105],f[105][105];//f数组记录的是走到当前位置的最优解
int main(){
    cin>>n;
    for (int i=1;i<=n;i++)
        for (int j=1;j<=i;j++) cin>>a[i][j];//读入
    f[1][1]=a[1][1];//初始化
    for (int i=2;i<=n;i++)
        for (int j=1;j<=i;j++)
        f[i][j]=max(f[i-1][j],f[i-1][j-1])+a[i][j];//走到第(i,j)的位置的最优解其实就是(i-1,j)和(i-1,j-1)中大的那个加上当前位置上的数字a[i][j];
    int maxx=-999999999;//打擂台前的稻草人
    for (int i=1;i<=n;i++)maxx=max(maxx,f[n][i]);//从最后一行选最大的
    cout<<maxx;
}

第二种

#include <bits/stdc++.h>
using namespace std;
int n,a[105][105],f[105][105];//同第一种一样,不过我们是倒着走
int main(){
    cin>>n;
    for (int i=1;i<=n;i++)
        for (int j=1;j<=i;j++) cin>>a[i][j];
    for (int i=1;i<=n;i++) f[n][i]=a[n][i];//初始化最后一层
    for (int i=n-1;i>=1;i--)
        for (int j=1;j<=i;j++)];
        f[i][j]=max(f[i+1][j],f[i+1][j+1])+a[i][j];//倒着走到第(i,j)的位置的最优解其实就是(i+1,j+1)和(i+1,j)中大的那个加上当前位置上的数字a[i][j];
    cout<<f[1][1];//最优解其实就是f[1,1]
}

今天讲的就是最简单的,下次我们即将讲基本动态规划的应用——背包
Kip和大家下次再见!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值