当前位置: 首页 > article >正文

动态规划---线性dp和区间dp

动态规划(三)

目录

  • 动态规划(三)
    • 一:线性DP
      • 1.数字三角形
        • 1.1数字三角形题目
        • 1.2代码思路
        • 1.3代码实现(正序and倒序)
      • 2.最长上升子序列
        • 2.1最长上升子序列题目
        • 2.2代码思路
        • 2.3代码实现
      • 3.最长公共子序列
        • 3.1最长公共子序列题目
        • 3.2代码思路
        • 3.3代码实现
      • 4.石子合并
        • 4.1题目如下
        • 4.2代码思路
        • 4.3代码实现
  • 总结

一:线性DP

1.数字三角形

1.1数字三角形题目

在这里插入图片描述

1.2代码思路

在这里插入图片描述

正序思路

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GCHTJR8G-1679754745663)(D:\acwing算法题目思路\acwing图片\image-20230313163539518.png)]

倒序思路

在这里插入图片描述

1.3代码实现(正序and倒序)

正序版本

#include<bits/stdc++.h>
using namespace std;

const int N=510,INF=0x3f3f3f3f;
int f[N][N];
int a[N][N];

int main(){
    int n;
    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++){             
        for(int j=0;j<=i+1;j++){          //因为有负数,所以应该将两边也设为-INF
            f[i][j]=-INF;
        }
    }

    f[1][1]=a[1][1];
    for(int i=2;i<=n;i++){
        for(int j=1;j<=i;j++){
            f[i][j]=a[i][j]+max(f[i-1][j-1],f[i-1][j]);
        }
    }

    int res=-INF;
    for(int i=1;i<=n;i++) res=max(res,f[n][i]);
    cout<<res<<endl;
}

倒叙版本(倒序比正序好的地方就在不用考虑边界问题)

#include<bits/stdc++.h>
using namespace std;

const int N=510;
int f[N][N];
int n;

int main(){
    cin>>n;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=i;j++){
            cin>>f[i][j];
        }
    }

    for(int i=n;i>=1;i--){
        for(int j=i;j>=1;j--){
            f[i][j]=max(f[i+1][j],f[i+1][j+1])+f[i][j];
        }
    }
    cout<<f[1][1]<<endl;
}

2.最长上升子序列

2.1最长上升子序列题目

在这里插入图片描述

2.2代码思路

在这里插入图片描述
在这里插入图片描述

2.3代码实现

#include<iostream>
#include<algorithm>
using namespace std;
const int N=1010;
int n;
int a[N],f[N];//a[N]我们用来保存长度为n的序列
                //f[N]表示以指定数字结尾的单调递增的序列的最大长度
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
    }
    for(int i=1;i<=n;i++)
    {
        f[i]=1;//只有a[i]一个数符合单调递增
        for(int j=1;j<i;j++)
        {
            if(a[j]<a[i])
            {
                f[i]=max(f[i],f[j]+1);
            }
        }
    }
    int res=0;
    for(int i=1;i<=n;i++)
    {
        res=max(res,f[i]);
    }
    printf("%d\n",res);
    return 0;
}

3.最长公共子序列

3.1最长公共子序列题目

在这里插入图片描述

3.2代码思路

在这里插入图片描述

我觉得这题的状态分成两半考虑比较方便,按两个序列末尾的字符是不是相等来区分。

在这里插入图片描述
在这里插入图片描述

3.3代码实现

#include<iostream>
#include<algorithm>
using namespace std;
 const int N=1010;
 int n,m;
 char a[N],b[N];
 int f[N][N];
 int main()
 {
     scanf("%d%d",&n,&m);
     scanf("%s%s",a+1,b+1);
     for(int i=1;i<=n;i++)
     {
         for(int j=1;j<=m;j++)
         {
             f[i][j]=max(f[i-1][j],f[i][j-1]);
             if(a[i]==b[j]) f[i][j]=max(f[i][j],f[i-1][j-1]+1);
         }
     }
     printf("%d\n",f[n][m]);
     return 0;
 }

4.石子合并

4.1题目如下

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lQ6plVYl-1679754745666)(D:\acwing算法题目思路\acwing图片\image-20230313171007224.png)]
题目分析
假设有4堆石子:1 3 5 2
i=1,k=2,j=4
f[1,2]:将第一堆和第二堆这两堆石子合并成一堆石子
f[3,4]:将第三堆和第四堆这两堆石子合并成一堆石子
所以经过f[1,2]+f[3,4]后我们就成功将1 3 5 2这四堆石子合并成了4 7 这两堆石子
不过别忘了题目要求的是将这四堆石子合并成一堆石子
所以我们还需将4 7 这两堆石子合并成一堆石子
因此还需付出4+7=11的代价;而11=[1,4]的前缀和
总代价:(1+3)+(5+2)+4+7=22
假设有4堆石子:1 3 5 2
i=1,k=2,j=4
f[1,2]:将第一堆和第二堆这两堆石子合并成一堆石子
f[3,4]:将第三堆和第四堆这两堆石子合并成一堆石子
所以经过f[1,2]+f[3,4]后我们就成功将1 3 5 2这四堆石子合并成了4 7 这两堆石子
不过别忘了题目要求的是将这四堆石子合并成一堆石子
所以我们还需将4 7 这两堆石子合并成一堆石子
因此还需付出4+7=11的代价;而11=[1,4]的前缀和
总代价:(1+3)+(5+2)+4+7=22

4.2代码思路

在这里插入图片描述

在这里插入图片描述

4.3代码实现

#include<iostream>
#include<algorithm>
using namespace std;
const int N=310;
int n;
int s[N];
int f[N][N];

int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&s[i]);
    for(int i=1;i<=n;i++) s[i]+=s[i-1];
    for(int len=2;len<=n;len++)
    {
        for(int i=1;i+len-1<=n;i++)
        {
            int l=i,r=i+len-1;
            f[i][r]=1e8;
            for(int k=l;k<r;k++)
            {
                f[l][r]=min(f[l][r],f[l][k]+f[k+1][r]+s[r]-s[l-1]);
            }
        }
    }
    printf("%d\n",f[1][n]);
    return 0;
}

总结

  本篇博客涉及了线性dp和区间dp,还有对应的算法题目讲解帮助理解算法,希望对大家有帮助~


http://www.kler.cn/a/3525.html

相关文章:

  • 解锁C# EF/EF Core:从入门到进阶的技术飞跃
  • 计算机网络介质访问控制全攻略:从信道划分到协议详解!!!
  • 梯度提升决策树树(GBDT)公式推导
  • blender 安装笔记 linux 2025
  • 前端【7】javascript-dom操作
  • opengrok_windows_环境搭建
  • STM32外设-定时器详解
  • QT之QSysInfo(查看电脑信息)
  • 【springcloud 微服务】Spring Cloud Alibaba Nacos使用详解
  • 如何成为优秀的程序员
  • 并发粗略测算
  • 6.3 归并排序Mergesort
  • 【深度强化学习】(3) Policy Gradients 模型解析,附Pytorch完整代码
  • 51单片机8*8 LED点阵实现原理讲解
  • echarts地图不同地区设置不同的颜色
  • 手机验证发送及其验证(基于springboot+redis)保姆级
  • Docker【基本使用】
  • 你还不会递归?告别困惑,我来教你
  • 多线程(三):Thread 类的基本属性
  • USB键盘实现——字符串描述符(四)
  • JNI原理及常用方法概述
  • 【软件测试】基础知识第一篇
  • 使用chatGPT实现数字自增动画
  • 数字信号处理_QA_2023_超长
  • [渗透教程]-004-嗅探工具-Nmap
  • STM32开发基础知识入门