动态规划-线性DP

1、数字三角形:

问题描述:

给定一个如下图所示的数字三角形,从顶部出发,在每一结点可以选择移动至其左下方的结点或移动至其右下方的结点,一直走到底层,要求找出一条路径,使路径上的数字的和最大。

        7

      3   8

    8   1   0

  2   7   4   4

4   5   2   6   5

输入描述:

第一行包含整数n, 表示数字三角形的层数。

接下来 n 行,每行包含若干整数,其中第 ii 行表示数字三角形第 i 层包含的整数。

输出描述:

输出一个整数,表示最大的路径数字和。


分析:

思路:关于一个位置上的数字嘛,从上往下看的话其实只有两种选择。

比如第 i 层(i≥2)上的数字,说破天就是该数字上第i-1层的数字选左边和右边最大的,如果没有两边直接加。

设一个二维数组为 dp[i][j],其中i表示层数,j表示该层第j个元素,dp[i][j]表示能走到第i层第j个元素所以路径上的数字的最大值(其中i≥1,i≥j≥1)。

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=510,INF=1e9;
int num[N][N];
int n,sum=-INF;
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)
    for(int j=1;j<=i;j++)
    cin>>num[i][j]; //输入
    
    for(int i=0;i<=n;i++)
    num[i][0]=num[i][i+1]=-INF; //边界值定义一个最小的值
    
    for(int i=2;i<=n;i++)
    for(int j=1;j<=i;j++)
    num[i][j]+=max(num[i-1][j-1],num[i-1][j]); //状态方程转移
    
    for(int i=1;i<=n;i++)
    sum=max(sum,num[n][i]); //寻找第n层所有的最大值
    
    cout<<sum;
    return 0;
}

该题也可以从下往上考虑,注意边界值设为最小,其状态转移方程为

num[i][j]+=max(num[i+1][j],num[i+1][j+1])

代码为:

#include<bits/stdc++.h>
using namespace std;
const int N=510;
int num[N][N];
int n;
int main()
{
    cin>>n;
    for(int i=1;i<=n;i++)
    for(int j=1;j<=i;j++)
    cin>>num[i][j]; //输入

    for(int i=n;i>=1;i--)
    for(int j=1;j<=i;j++)
    num[i][j]+=max(num[i+1][j],num[i+1][j+1]); //从下往上状态转移

    cout<<num[1][1];
    return 0;
}

2、最长上升子序列:

问题描述:

给定一个长度为N的数列,求数值严格单调递增的子序列的长度最长是多少。

输入格式
第一行包含整数N
第二行包含N个整数,表示完整序列。
输出格式
输出一个整数,表示最大长度。

分析:

关于最长上升子序列,本质上就是维护一个数组 dp【i】,其中 dp【i】代表 前i个元素中的最长上升长度。

如何去维护呢?

本质上就是 把第i个元素和前面i个元素比较,比较 把第i个元素 插入到 第 1个元素到第 i-1个元素后面之后的dp【i】长度,尽可能使其最大即可,暴力解法如下,时间复杂度 差不多是 n方

代码如下:


                
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值