区间一维dp史上最细总结(绝对干货,还不会的一定要进来)

news2024/10/6 2:23:18

那年初夏(三)

注:此部分仅为娱乐和引入用,与本文没有太大关联,可以跳过,阅读下面的正文部分。

上篇出现于:DFS(深度优先搜索)详解(概念讲解,图片辅助,例题解释,剪枝技巧)​​​​​​

        孙翱走着,忽然想起,局长听到他一句话后,脸色有些不对劲。“难道……”,这想着,迎面撞上一个人。

        “不好意思”,撞他的是一个年轻的警员,“我正在想如何完成组长布置的 统计犯罪率 最长上升子序列的任务”。

        “哦?你们竟然没有工具,那么原始!我来教你,用动态规划就行,不过涉及到区间动态规划”……

        那位警员,给孙翱点谢金。孙翱拿去买酒,喝完已是深夜。孙翱回到家,酒气冲头,倒头就睡,甚至忘了巡逻……

        四周一下子静了下来。那弯诡异的钩月早已不知不觉的把自己藏进云层里,仿佛在恐惧着什么。惨白的光立即变成了无底的暗。天愈黑了,翻滚着的阴云带着梦魇遮住仅有的一点点光。万物都在随风发抖。

        一人,站于墓前,黑暗之中,喃喃自语;一人,藏于丛中,冷风之中,紧握手枪。

        丛中人,披一黑色衣,紧盯墓前人。

        很久之前,我还远超于他。但,不知怎么的,他突飞猛进,将我甩到身后。我不断努力,想要反超,但总超不过。

         超不过,就模仿他,成为他。

        我不断模仿他,想成为他,但,不可能。学业、事业、爱情,我都不及他。无论怎么模仿,怎么学习,怎么努力。

       模仿不了,就毁灭他,替代他。

        丛中人缓缓举起枪。

        ”砰“,孙翱猛然惊醒,一身冷汗。


引入

        还是那个问题:

1.动态规划是什么?

动态规划(英语:Dynamic programming,简称 DP),是一种在数学、管理科学、计算机科学、经济学和生物信息学中使用的,通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法。动态规划常常适用于有重叠子问题和最优子结构性质的问题。

百度的还是那么严谨枯燥,简单来说,动态规划即:
 

通过将问题拆分成一个一个小问题,记录过往结果,减少重复运算。

2.什么是区间动态规划问题? 

定义

区间类动态规划是线性动态规划的扩展,它在分阶段地划分问题时,与阶段中元素出现的顺序和由前一阶段的哪些元素合并而来有很大的关系。

性质

区间 DP 有以下特点:

合并:即将两个或多个部分进行整合,当然也可以反过来;

特征:能将问题分解为能两两合并的形式;

求解:对整个问题设最优值,枚举合并点,将问题分解为左右两个部分,最后合并两个部分的最优值得到原问题的最优值。

3.为何总是要问这种问题?

为何我总是不厌其烦地问这类问题,这种充满概念性的问题?因为,概念是实践的基础。

只有理解了概念,才能完美实践。

动态规划,懂了“通过将问题拆分成一个一个小问题,记录过往结果,减少重复运算。”这句话,就全都会有头绪。重点请看下面的:动态规划基本步骤


区间动态规划基本 思考 步骤(划重点)

这部分,与网上其他的文章都不同,绝对通俗易懂(有点自信)

1.理解题目

2.定义dp[i]或dp[i][j]表示的是什么(通常为 题目要求的东西 的 局部最优解

3.用递归(暴力)的思想分析每一步该怎么做

4.再就递归的思想,确认dp[i]或dp[i][j] 如何得到,由何得到

5.由上得到动态转移方程,并验证

6.思考代码如何实现(考虑细节、输入输出等)


例题精讲

都说,实践出真知,那我们就实践一下。

1.最长上升子序列

题目描述

【题意】

    有n个整数组成的数列,记为: a1、a2、…、an。例如:3,18,7,14,10,12,23,41,16,24。

    如果从中挑出3、18、23、24,并且保留其原有的先后顺序,就是一个长度为4的上升序列;如果挑出3、7、10、12、16、24,,并且保留其原有的先后顺序,则是长度为6的上升序列。

    求出最长的上升序列的长度。

【输入格式】

    第一行一个整数n(1≤n≤1000),下来n个整数。

【输出格式】

    最长上升子序列的长度。

【样例输入】

10

3 18 7 14 10 12 23 41 16 24

【样例输出】

6

思路:

这是一道很经典的一维区间动态规划题。按照我上面的步骤,一步步来做吧!

题目很简洁,不用理解了。

首先,定义dp[i]或dp[i][j]表示的是什么(通常为 题目要求的东西 的 局部最优解)。既然是求一条数字串的最长上升子序列长度,那么其局部最优解就是第i个数的最长上升子序列长度,则a[i]表示包含并第i个数以此为结尾的最长上升子序列长度,因此初始化为1。

然后,用递归(暴力)的思想分析每一步该怎么做。很显然,暴力没什么方法。。。

之后,再就递归的思想,确认dp[i]或dp[i][j] 如何得到,由何得到

对于状态f[i],因为i位置前的每个位置都可能是它上一阶段的状态,所以我们需要从0到i遍历array序列,设遍历到的位置为j,那么:

如果a[i]>a[j],其能做出的决策有:
a[i]加入最长上升子序列
a[i]不加入最长上升子序列:则f[i]=1;
  很显然,能加入一定加入,因为它肯定比不加入好。

如果a[i]<=a[j],其能做出的决策只能是:
a[i]不加入最长上升子序列:则f[i]=1;
————————————————
参考自:
最长上升子序列(LIS)问题的解决及优化_最长上升子序列优化_默归的博客-CSDN博客

在此以后,由上得到动态转移方程,并验证

因为求的是“最长”,因此,用max取大

那么,可得:

(验证就免了。。。) 

最后,思考代码如何实现

第二种情况不会改变f[i],因此就免了。

这里,有一个细节有注意,a[i]表示的是包含并第i个数以此为结尾的最长上升子序列长度,而最长的未必包含最后一个数,因此不能直接输出f[n],而应比较取f[1]-f[n]的最大值,为答案。这个可在循环中完成。

代码

#include<bits/stdc++.h>
using namespace std;
int a[1005],f[1005],m,n,maxx=-1;
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;
		for(int j=i;j>=1;j--)
		{
			if(a[i]>a[j]) f[i]=max(f[i],f[j]+1);
		}
		maxx=max(maxx,f[i]);
	}
	cout<<maxx;//偷懒 
}

2.拦截导弹

题目描述

【题意】
      某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统。但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度。
      某天,雷达捕捉到敌国的导弹来袭。由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹。
      输入导弹依次飞来的高度(雷达给出的高度数据是不大于30000的正整数,导弹数不超过1000),计算这套系统最多能拦截多少导弹,如果要拦截所有导弹最少要配备多少套这种导弹拦截系统。
【输入格式】
     输入导弹依次飞来的高度。
【输出格式】
     第一行:最多能拦截的导弹数;
     第二行:要拦截所有导弹最少要配备的系统数。
【输入样例】
389 207 155 300 299 170 158 65
【输出样例】
6
2
【来源】Noip1999

思路 :

这道题考的是语文

问题抽象(这里用到了 第一步——理解题目):

1.求最多可以拦截的导弹数,就是求最长递减字串长度
2.求最少的系统数,就是求最长不下降字串的长度。可以这样理解,假设最长的非递减字串长度为n, 那么以这最长的非递减字串的每个字符为分界点,可以将整个串分成n个小递减的小字串,这样每一发炮弹都可以拦截对应的小字串,倘若最长的非递减字串长大于n, 那么势必会有一个小字串不是递减的,则这个字串就要用不止一发子弹才能打下。

好了,理解了题目,后面算法就很简单了,不讲了(不过还要放张图,防止那些“聪明人”)!

 参考:详解拦截导弹问题(动态规划)_Junieson的博客-CSDN博客

代码

#include<bits/stdc++.h>
using namespace std;
int a[1100],fup[1100],fdn[1100],n;
int main()
{
while(scanf("%d",&a[++n])!=EOF);
    fup[0]=0;
    for(int i=1;i<=n;i++)
    {
        fup[i]=1;
        for(int j=i-1;j>=1;j--)
            if(a[i]>a[j])
                fup[i]=max(fup[i],fup[j]+1);
    }
    fdn[n+1]=0;
    for(int i=n;i>=1;i--)
    {
          
        fdn[i]=1;
        for(int j=i+1;j<=n;j++)
            if(a[i]>=a[j])
                fdn[i]=max(fdn[i],fdn[j]+1);
    }
    int s1=0,s2=0;for(int i=1;i<=n;i++) s1=max(s1,fup[i]),s2=max(s2,fdn[i]);
    printf("%d\n%d\n",s2-1,s1);
    return 0;
}

3.护卫队

题目描述

【题意】(本题附有视频)
    护卫车队在一条单行的街道前排成一队,前面河上是一座单行的桥。因为街道是一条单行道,所以任何车辆都不能超车。桥能承受一个给定的最大承载量。为了控制桥上的交通,桥两边各站一个指挥员。护卫车队被分成几个组,每组中的车辆都能同时通过该桥。当一组车队到达了桥的另一端,该端的指挥员就用电话通知另一端的指挥员,这样下一组车队才能开始通过该桥。每辆车的重量是已知的。任何一组车队的重量之和不能超过桥的最大承重量。被分在同一组的每一辆车都以其最快的速度通过该桥。一组车队通过该桥的时间是用该车队中速度最慢的车通过该桥所需的时间来表示的。问题要求计算出全部护卫车队通过该桥所需的最短时间值。
【输入格式】
    第一行包含三个正整数(用空格隔开),第一个整数表示该桥所能承受的最大载重量W(用吨表示);第二个整数表示该桥的长度L(用千米表示);第三个整数表示该护卫队中车辆的总数(n<1000)。接下来的几行中,每行包含两个正整数w和v(用空格隔开),w表示该车的重量(用吨表示,车的重量在int的范围内),v表示该车过桥能达到的最快速度(用千米/小时表示)。车子的重量和速度是按车子排队等候时的顺序给出的。
【输出格式】
    输出一个实数,四舍五入精确到小数点后1位,表示整个护卫车队通过该桥所需的最短时间(用分钟表示)。
【样例输入】
100 5 10
40 25
50 20
50 20
70 10
12 50
9 70
49 30
38 25
27 50
19 70
【样例输出】
75.0

思路 

第一步,理解题目。在去其糟粕(几乎全是糟粕)后,可得出:

1.所有车无论怎么分组,不用考虑排序

 2.任何一组车队的重量之和不能超过桥的最大承重量(边界条件)

 3.一组车队通过该桥的时间是用该车队中速度最慢的车通过该桥所需的时间来表示的

第二步,定义dp[i]或dp[i][j]表示的是什么。f[i]表示1-i辆车通过桥所需的最短时间 

……

后面的以后再搞(注释写得很细,自己看)

代码

#include<bits/stdc++.h>
using namespace std;
double W,L,v[1100],w[1100],zw[1100],f[1100];
//f[i]表示第i辆车通过桥所需的最短时间 
int n;
int main()
{
    scanf("%lf%lf%d",&W,&L,&n); 
    for(int i=1;i<=n;i++)
    {
        scanf("%lf%lf",&w[i],&v[i]);
        v[i]/=60;//因为输出的单位要求是分钟 
        zw[i]=zw[i-1]+w[i];//zw[i]表示从第一辆到第i辆车的总重 
    }
    for(int i=1;i<=n;i++)
    {
        double vm=f[i]=0x3f3f3f3f3f3f3f3f;//因为都应为最小值,因此初始化为最大值 
        for(int j=i;j>=1;j--)
        {
            vm=min(vm,v[j]);//寻找最慢速的车。
            //vm表示车队的速度,因为最慢速的车在车队的时间中唯一有参考价值 
            if(zw[i]-zw[j-1]<=W)//设此车队区间为j~i,若其总重小于等于w,则可行。 
            {
                f[i]=min(f[i],f[j-1]+L/vm); 
                //f[j-1]表示1~j-1辆车的最短时间,l/vm表示分j~i为车队的时间。 
            }
        }
    }
    printf("%.1lf",f[n]);
}

 4.最大子段和

题目描述

【题意】
给定一个n个数ai,求最大子段和:连续一段和S=a[i]+a[i+1]+……+a[j](1<=i<=j<=n),求S的最大值。
【输入格式】
第一行一个整数n( 1<= n <= 10^6)。
下来给出n个整数ai(|ai|<=10^3)。
【输出格式】
一行一个整数,表示最大子段和。
【样例输入】
6
-20 11 -4 13 -5 -2
【样例输出】
20

思路 

设:f[i]表示,包含a[i]并以其为结尾的最大连续和

大于0,就会越来越大;反之,小于即越来越小

那,大于0则加,小于则为a[i]自己。(一重循环,因为是连续的)

同样要注意,a[i]表示的是包含并第i个数以此为结尾的最大字段和,而最长的未必包含最后一个数,因此不能直接输出f[n],而应比较取f[1]-f[n]的最大值,为答案。这个可在循环中完成。

代码

#include<bits/stdc++.h>
using namespace std;
int n,a[1000005],f[1000005],maxx=-10005;
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    for(int i=1;i<=n;i++)
    {
        if(f[i-1]>0) f[i]+=a[i]+f[i-1];
        else f[i]=a[i];
        maxx=max(maxx,f[i]);
    }
    printf("%d",maxx);
}

最后

写文章不易,求点赞+评论(骂骂作者也不错)

谢谢!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/185421.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

HashSet源码分析

一、HashSet继承关系 1、继承 public boolean equals(Object o) {if (o this)return true;// o没有实现Set接口&#xff0c;返回falseif (!(o instanceof Set))return false;// 向下转换Collection<?> c (Collection<?>) o;// 元素个数不相等&#xff0c;返回f…

4.组件通讯

默认情况下组件只能使用自己的状态&#xff0c;但当组件拆分的比较小的时候&#xff0c;就不可避免的使用到其他组件的状态&#xff0c;比如之前做的例子&#xff0c;当我们的发表评论区域与显示评论区域拆分为两个组件时&#xff0c;这两个组件之间一定要进行通讯以达成某些功…

π122M30代替Si8621AB-B-IS 低功耗,高能效、抗干扰能力好的 双通道数字隔离器解决方案

π122M30代替Si8621AB-B-IS 低功耗&#xff0c;高能效、抗干扰能力好的解决方案电路简单、稳定性更高 &#xff0c;具有出色的性能特征和可靠性&#xff0c;整体性能优于光耦和基于其他原理的数字隔离器产品。 产品传输通道间彼此独立&#xff0c;可实现多种传输方向的配置&…

Day11 C++STL入门基础知识八——stack、queue容器 基本概念-常用接口 【全面深度剖析+例题代码展示】

&#x1f483;&#x1f3fc; 本人简介&#xff1a;男 &#x1f476;&#x1f3fc; 年龄&#xff1a;18 &#x1f6a9; 今日留言&#xff1a;亮亮被迫去练科目二啦&#xff0c;定时发布的文章&#xff0c;回来统一给大家三连回复嗷~&#x1f609; 文章目录1. stack容器——栈1.…

CSDN常见问题汇总

1.怎么申请退款&#xff1f; 通过CSDN平台购买的“VIP会员、余额”&#xff0c;在刚购买后未使用的情况可支持退款&#xff1b; “付费资源、付费专栏、盲盒、魔盒、课程、C认证”等虚拟商品一经购买后&#xff0c;除了特殊原因外&#xff0c;概不支持退款&#xff1b; 特殊原…

美团8年测试经验,一文手把手教你抒写接口测试框架集成测试报告

在接口自动化测试完成后&#xff0c;通常我们都需要一个测试报告来进行结果展示&#xff0c;而测试报告的美观程度直接决定了你在同事和领导眼中的技术形象&#xff0c;本文将介绍rest-assured接口测试框架集成ExtentReports测试报告&#xff0c;让你的框架更加完美。 ExtentR…

【大唐杯备考】——5G网元功能与接口(学习笔记)

&#x1f4d6; 前言&#xff1a;本期介绍5G网元功能与接口。 目录&#x1f552; 1. 5G移动通信系统整体网络架构&#x1f558; 1.1 5G核心网架构&#x1f558; 1.2 5G接入网架构&#x1f552; 2. 5G主要网元功能&#x1f558; 2.1 UPF&#xff08;用户面功能&#xff09;&#…

使用code-server为Docker容器搭建在线开发环境

Code-server是一个基于服务端的开源VSCode。只要服务器端配置好code-server&#xff0c;就可以在任何浏览器上使用VScode访问服务器的代码进行编程。&#xff08;GitHub地址&#xff1a;https://github.com/cdr/code-server&#xff09; Docker是一个开源的Linux容器引擎。我们…

DeepLabV3+:搭建Mobilenetv2网络

目录 Mobilenetv2的介绍 Mobilenetv2的结构 Inverted Residual Block倒残差结构 Pytorch实现Inverted Residual Block 搭建Mobilenetv2 Pytorch实现Mobilenetv2主干网络 相关参考资料 Mobilenetv2的介绍 Mobilenetv2网络设计基于Mobilenetv1&#xff0c;它保持了其简单…

【进击的算法】动态规划——01背包

&#x1f37f;本文主题&#xff1a;动态规划 01背包 背包问题 C/C 算法 &#x1f388;更多算法&#xff1a;基础回溯算法 基础动态规划 &#x1f495;我的主页&#xff1a;蓝色学者的主页 文章目录一、前言二、概念✔️动态规划概念✔️01背包的概念三、问题描述与讲解&#x1…

spring 中 mybaits 的一级缓存失效

mybatis 的一级缓存 简单回顾下mybatis的一级缓存 本质上是一个基于map实现的内存级别的缓存&#xff0c;默认开启&#xff0c;生命周期是 sqlsession 级别的 为什么会失效 其实这个问题反向分析一下就会有思路了&#xff0c;一级缓存默认是sqlsession级别的&#xff0c;这个规…

2022年rust杂记

以下记录的是&#xff0c;我在学习中的一些学习笔记&#xff0c;这篇笔记是自己学习的学习大杂烩&#xff0c;主要用于记录&#xff0c;方便查找1、相关学习链接https://www.rust-lang.org/zh-CN/governance/ RUST 官网博客https://kaisery.github.io/trpl-zh-cn/&#xff08;最…

应用性能监控对DMS系统综合分析案例

背景 DMS系统是某汽车集团的经销商在线系统&#xff0c;是汽车集团的重要业务系统。本次分析重点针对DMS系统性能进行分析&#xff0c;以供安全取证、性能分析、网络质量监测以及深层网络分析。 该汽车总部已部署NetInside流量分析系统&#xff0c;使用流量分析系统提供实时和…

好好的系统,为什么要分库分表?

不急于上手实战 ShardingSphere 框架&#xff0c;先来复习下分库分表的基础概念&#xff0c;技术名词大多晦涩难懂&#xff0c;不要死记硬背理解最重要&#xff0c;当你捅破那层窗户纸&#xff0c;发现其实它也就那么回事。 什么是分库分表 分库分表是在海量数据下&#xff0…

51单片机学习笔记-14 ADDA

14 ADDA [toc] 注&#xff1a;笔记主要参考B站江科大自化协教学视频“51单片机入门教程-2020版 程序全程纯手打 从零开始入门”。 注&#xff1a;工程及代码文件放在了本人的Github仓库。 14.1 AD/DA简介 14.1.1 AD/DA基本介绍 AD&#xff08;Analog to Digital&#xff09;…

FreeRTOS任务管理

RTOS 的核心是如果高效管理各个任务及任务之间通信&#xff0c;本章将向大家介绍 FreeRTOS 的任务管理&#xff0c;通过本章的学习&#xff0c;让大家对 RTOS 任务的理解更加深入&#xff0c; 为后面的学习做好铺垫。本章分为如下几部分内容&#xff1a; 1 任务管理介绍 2 常用…

ue4c++日记7(动画蓝图)

FVector Speed Pawn->GetVelocity();//获取方向向量FVector xyspeed FVector(Speed.X, Speed.Y,0);//不要z方向MovementSpeed xyspeed.Size();//xy取长//角色是否处于下落状态IsJumping Pawn->GetMovementComponent()->IsFalling();//#include "GameFramewor…

FreeRTOS中的信号量实验

信号量是操作系统中重要的一部分&#xff0c;信号量一般用来进行资源管理和任务同 步&#xff0c;FreeRTOS 中信号量又分为二值信号量、计数型信号量、互斥信号量和递归 互斥信号量。不同的信号量其应用场景不同&#xff0c;但有些应用场景是可以互换着使用。 本章要实现的功能…

【数据结构从0到1之树的初识】

目录 1.树的表达方式 1.1 树的定义 1.2树的相关概念 1.3树的存储结构 1.3.1 双亲表示法 1.3.2 孩子表示法 1.3.3 孩子兄弟表示法 1.4树在实际中的应用 后记&#xff1a; &#x1f57a;作者&#xff1a; 迷茫的启明星 &#x1f618;欢迎关注&#xff1a;&#x1f44d;点…

Lua 迭代器

Lua 迭代器 参考文章&#xff1a; 菜鸟教程。 https://cloud.tencent.com/developer/article/2203215 迭代器&#xff08;iterator&#xff09;是一种对象&#xff0c;它能够用来遍历标准模板库容器中的部分或全部元素&#xff0c;每个迭代器对象代表容器中的确定的地址。 在 L…