斜率优化DP——AcWing 303. 运输小猫

斜率优化DP

定义

斜率优化DP(Slope Optimization Dynamic Programming)是一种高级动态规划技巧,用于优化具有特定形式的状态转移方程。它主要应用于那些状态转移涉及求极值(如最小值或最大值)的问题中,通过分析状态转移函数的斜率特性,将原本需要进行多次比较的操作转化为对斜率的管理,从而减少计算量。斜率优化的核心在于利用函数的单调性,通过维护一个数据结构(如单调队列)来避免重复计算,达到优化的目的。

运用情况

  1. 最优化问题:当动态规划的状态转移涉及求解最小值或最大值,且转移方程可表达为线性或近似线性关系时。
  2. 序列问题:例如,在序列中选择一段区间,使得区间内满足某种条件的子序列和最大或最小。
  3. 费用最小化问题:如求解完成某任务序列的最小花费,其中选择下一个任务的成本可能依赖于之前的选择。
  4. 具有特殊结构的问题:如某些问题的状态转移可以通过分析状态间的关系转换为斜率的比较和更新。

注意事项

  1. 状态和转移方程:明确问题的状态定义和状态转移方程,确保它们适合斜率优化。
  2. 单调性分析:分析状态转移函数的斜率变化,确定如何维护一个单调队列或其他数据结构来避免无效计算。
  3. 边界处理:注意处理状态转移的边界条件,特别是状态转移开始和结束时的特殊情况。
  4. 数据结构选择:根据问题的具体情况选择合适的数据结构(如单调队列)来维护关键信息。
  5. 复杂度控制:确保斜率优化后的时间复杂度优于原始DP,避免过度优化导致的复杂度上升。

解题思路

  1. 理解问题:首先,深入理解问题背景和求解目标,识别出问题是否适合斜率优化。
  2. 状态定义:定义合适的DP状态和状态转移方程,注意状态转移应能表达为某种极值问题。
  3. 斜率分析:分析状态转移方程中涉及的变量关系,识别出与“斜率”相关的模式,如线性函数、单调性等。
  4. 设计优化策略:根据斜率特性设计数据结构(通常是单调队列)来维护中间状态,避免重复计算。
  5. 实现代码:编写代码实现动态规划过程,同时集成斜率优化机制,注意正确处理边界和特殊情况。
  6. 验证与优化:测试代码,确保正确性,并根据实际情况调整优化策略以进一步提高效率。

AcWing 303. 运输小猫

题目描述

AcWing 303. 运输小猫 - AcWing

运行代码

#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

typedef long long LL;

const int N = 100010, M = 100010, P = 110;

int n, m, p;
LL d[N], t[N], a[N], s[N];
LL f[P][M];
int q[M];

LL get_y(int k, int j)
{
    return f[j - 1][k] + s[k];
}

int main()
{
    scanf("%d%d%d", &n, &m, &p);

    for (int i = 2; i <= n; i ++ )
    {
        scanf("%lld", &d[i]);
        d[i] += d[i - 1];
    }

    for (int i = 1; i <= m; i ++ )
    {
        int h;
        scanf("%d%lld", &h, &t[i]);
        a[i] = t[i] - d[h];
    }

    sort(a + 1, a + m + 1);

    for (int i = 1; i <= m; i ++ ) s[i] = s[i - 1] + a[i];

    memset(f, 0x3f, sizeof f);
    for (int i = 0; i <= p; i ++ ) f[i][0] = 0;

    for (int j = 1; j <= p; j ++ )
    {
        int hh = 0, tt = 0;
        q[0] = 0;

        for (int i = 1; i <= m; i ++ )
        {
            while (hh < tt && (get_y(q[hh + 1], j) - get_y(q[hh], j)) <= a[i] * (q[hh + 1] - q[hh])) hh ++ ;
            int k = q[hh];
            f[j][i] = f[j - 1][k] - a[i] * k + s[k] + a[i] * i - s[i];
            while (hh < tt && (get_y(q[tt], j) - get_y(q[tt - 1], j)) * (i - q[tt]) >=
                (get_y(i, j) - get_y(q[tt], j)) * (q[tt] - q[tt - 1])) tt -- ;
            q[ ++ tt] = i;
        }
    }

    printf("%lld\n", f[p][m]);

    return 0;
}

代码思路

  1. 输入处理:

    • 首先读入山的数量 n、猫的数量 m、饲养员的数量 p
    • 然后读入每两座相邻山之间的距离,并累加得到从1号山到每座山的总距离 d[]
    • 对于每只猫,读入它停留的山的编号 h 和停止玩耍的时刻 t,并计算出相对于1号山的等待时间差 a[i] = t[i] - d[h]
    • 对这些等待时间差进行排序,同时计算累积和 s[]
  2. 动态规划初始化:初始化二维数组 f[j][i] 来存储前 i 只猫被前 j 个饲养员接走的最小等待时间总和。这里 f[j][0] = 0,表示没有猫时等待时间为0。

  3. 单调队列优化动态规划:

    • 使用单调递减的队列 q[] 来存储可能成为最优解的状态索引。队列中的元素代表当前考虑的猫的下标。
    • 遍历每增加一个饲养员 (j 从1到 p) 的情况,对于每只猫 (i 从1到 m),计算将其加入到当前饲养员的最优解中需要增加的等待时间。
    • 通过维护队列保证每次选择的都是可能产生最小等待时间的猫的组合。队列中的更新基于斜率(即增加一个猫带来的收益变化)来进行,确保队头总是最优解的一部分。
    • 计算 f[j][i] 时,利用队列中的信息避免重复计算,实现状态转移的优化。
  4. 输出结果:最终答案存储在 f[p][m] 中,即所有猫被 p 个饲养员接走的最小等待时间总和。

改进思路

  1. 内存优化:当 M 和 P 的值较大时,f[P][M] 的空间复杂度可能较高。可以考虑滚动数组或者只保留必要的状态来减少空间使用。例如,由于状态转移只与前一状态有关,可以只保留两行或一维数组来交替存储上一行和当前行的状态。

  2. 细节优化:在计算斜率时,直接计算斜率可能导致浮点运算,影响效率和精度。可以通过比较差值而非直接计算斜率来优化,即比较 (f[j-1][k] - f[j-1][k-1]) 与 (a[k] - a[k-1]) 来判断单调性,避免浮点运算。

  3. 输入处理的效率:对于大数组的读入,可以考虑使用更快的IO方式,如 scanf 替换为 read 加缓冲读取,或者使用 ios::sync_with_stdio(false) 禁用C++标准库与C标准库的同步,提升读写速度。

  4. 避免重复计算:确认在计算斜率和更新状态时,是否有进一步的重复计算可以避免。例如,是否可以通过更精细的数据结构或额外的变量来避免某些全局查找或重复的计算过程。

  5. 代码可读性和维护性:

    • 添加更多的注释,特别是对于算法核心逻辑和复杂的数据结构操作部分,提高代码的可读性和后期维护的便捷性。
    • 函数化拆分复杂的逻辑,比如将单调队列的维护、状态转移逻辑封装成单独的函数,使代码结构更加清晰。
  6. 性能测试与瓶颈分析:实施性能测试,确定程序的瓶颈所在,可能是I/O操作、内存访问、或是特定的计算环节。根据测试结果,针对性地进行优化。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

c++重载(运算符)

1&#xff09;C入门级小知识&#xff0c;分享给将要学习或者正在学习C开发的同学。 2&#xff09;内容属于原创&#xff0c;若转载&#xff0c;请说明出处。 3&#xff09;提供相关问题有偿答疑和支持。 对于系统的所有操作符&#xff0c;一般情况下&#xff0c;只支持基本数…

ubuntu安装显卡驱动

获取权限 chmod X NVIDlA-Linux-x86_64-550.90.07.run 安装程序 sudo bash NVIDlA-Linux-x86_64-550.90.07.run

告别模糊时代,扫描全能王带来清晰世界

模糊碑文引发的思考 上个月中旬去洛阳拜访了著名的龙门石窟&#xff0c;本就对碑文和文字图画感兴趣的我们&#xff0c;准备好好欣赏一下龙门石窟的历史文化古迹。到了地方之后&#xff0c;我发现石窟的高度和宽度远远超出了想象&#xff0c;正因如此&#xff0c;拍出来的文字…

多多代播24小时值守:电商直播时代是带货爆单的关键

在电商直播盛行的今天&#xff0c;直播带货已成为品牌与消费者沟通的关键。然而&#xff0c;流量波动大&#xff0c;竞争激烈&#xff0c;使品牌面临诸多挑战。因此&#xff0c;许多品牌寻求专业代播服务&#xff0c;并特别强调24小时值守的重要性。 流量来源的不稳定性是一个显…

Spring-循环依赖是如何解决的

1、bean被创建保存到spring容器的过程 1、实例化 -> 获取对象&#xff1b; 2、填充属性&#xff1b;这里可能需要依赖其它的bean。 3、AOP代理对象替换&#xff1b; 4、加入单例池&#xff1b; 问题&#xff1a; 循环依赖怎么处理 ServiceA 中有属性ServiceB b&#…

使用label-studio对OCR数据进行预标注

导读 label-studio作为一款数据标注工具相信大家都不陌生&#xff0c;对于需要进行web数据标注协同来说应该是必备工具了&#xff0c;标注的数据类型很全涉及AI的各个任务(图像、语音、NLP、视频等)&#xff0c;还支持自定义涉及模版。 然而&#xff0c;我们在标注数据的过程…

win11 内存占用过大优化尝试

关闭开机加速 wins打开搜索 控制面板&#xff0c;打开控制面板 找到硬件和声音-电源选项-选择电源按钮的功能-去掉勾选启用快速启动 关闭windows 更新 winr 输入services.msc打开服务-搜索windows 更新-双击打开设置-选择禁用 貌似没什么用。

【Python3的内置函数和使用方法】

目录 Python 特点 Python 中文编码 Python 变量类型 Python列表 Python 元组 元组是另一个数据类型&#xff0c;类似于 List&#xff08;列表&#xff09; Python 字典 Python数据类型转换 Python 运算符 Python算术运算符 Python比较运算符 Python赋值运算符 Pyt…

根据描述表示泥浆密度沿着管路的长度方向在不断变化,如何来表示泥浆密度随管路的变化?

&#x1f3c6;本文收录于《CSDN问答解答》专栏&#xff0c;主要记录项目实战过程中的Bug之前因后果及提供真实有效的解决方案&#xff0c;希望能够助你一臂之力&#xff0c;帮你早日登顶实现财富自由&#x1f680;&#xff1b;同时&#xff0c;欢迎大家关注&&收藏&…

文件夹内-资源名称前加序号排列

问题&#xff1a;在文件夹下的资源可以按时间排序&#xff0c;导入unity后资源顺序会乱掉&#xff0c;不方便按顺序赋值&#xff0c;为了方便&#xff0c;通过下面方法在文件夹下统一在资源名称前按顺序加上序号 win11在文件夹内右键&#xff0c;选择——在终端中打开 输入&a…

4.SQL注入-xx型

SQL注入-xx型 输入kobe查询&#xff0c;同样展示id和邮箱 xx型的sql语句查询方式&#xff0c;猜测 select 字段1,字段2 from 表名 where username(kobe)在后台语句中的查询 select id,email from member where username(kobe);根据上图构造payload语句为 username(kobe) …

spring-security安全框架(超精细版附带流程讲解图)

目录 一、回顾一下 二、security使用 2.1 覆盖掉默认配置「自定义配置」 2.2 如何自定义认证 2.3 纯纯自定义 2.4 jwt 2.5 官网认证流程 2.6 RBAC模型 4.1. 创建表结构 2.7 如何实现权限流程 一、回顾一下 security干啥的? 认证和授权 使用方式 引入依赖, 基于spri…

【自然资源】国家历史文化名城你知道多少?

【自然资源】国家历史文化名城你知道多少&#xff1f; 中国五千年的历史孕育出了一些因深厚的文化底蕴和发生过重大历史事件而青史留名的城市。根据《中华人民共和国文物保护法》&#xff0c;“历史文化名城”是指保存文物特别丰富&#xff0c;具有重大历史文化价值和革命意义…

小红书多账号管理平台哪个好用?可以快速监测多个小红书账号的数据吗?

随着品牌营销战线的不断扩展&#xff0c;小红书已经成为企业和个人品牌竞相展示的舞台。但是&#xff0c;随之而来的多账号管理问题也让众多运营者头疼不已。一个优秀的多账号管理平台&#xff0c;能让你事半功倍&#xff0c;轻松监控和分析账号数据。 如今&#xff0c;市面上出…

昇思25天学习打卡营第12天 | ResNet50图像分类

内容介绍&#xff1a; ResNet50网络是2015年由微软实验室的何恺明提出&#xff0c;获得ILSVRC2015图像分类竞赛第一名。在ResNet网络提出之前&#xff0c;传统的卷积神经网络都是将一系列的卷积层和池化层堆叠得到的&#xff0c;但当网络堆叠到一定深度时&#xff0c;就会出现…

NPOI入门指南:轻松操作Excel文件的.NET库

目录 引言 一、NPOI概述 二、NPOI的主要用途 三、安装NPOI库 四、NPOI基本使用 六、性能优化和内存管理 七、常见问题与解决方案 八、结论 附录 引言 Excel文件作为数据处理的重要工具&#xff0c;广泛应用于各种场景。然而&#xff0c;在没有安装Microsoft Office的…

JavaScript面试宝典

栈和堆的区别 栈(stack)&#xff1a; 栈是内存的简称&#xff0c;栈是自动分配相对固定大小的内存空间&#xff0c;并由系统自动释放&#xff0c;栈数据结构遵循FILO&#xff08;first in last out&#xff09;先进后出的原则。 堆(heap)&#xff1a; 是堆内存的简称&#xff…

【杂说咋说】中国历史上最古老的十大建筑​,看看你都去过几个?

【杂说咋说】中国历史上最古老的十大建筑​&#xff0c;看看你都去过几个&#xff1f; 中国作为世界四大文明古国之一&#xff0c;历史文化源远流长。在几千年的历史变迁中&#xff0c;中华先祖在神州大地上留下了无数遗迹&#xff0c;其中包括很多古建筑。本期就来介绍一下中…

Pinia详解

文章目录 简介特点用法1. 安装Pinia2. 注册Pinia Store3. 创建Pinia Store4. 使用Pinia Store 区别 Vuex详解 Pinia是一个基于Vue 3的状态管理库&#xff0c;专为Vue 3设计。它提供了一种简单、直观且可扩展的方式来组织和访问应用程序的状态。Pinia的设计灵感来源于Vuex&#…

【proteus经典实战】16X192点阵程序

一、简介 6X192点阵程序通常用于表示高分辨率图像或文字&#xff0c;其中16X表示像素阵列的宽度&#xff0c;192表示每个像素阵列中的点阵数&#xff0c;16X192点阵程序需要一定的编程知识和技能才能编写和调试&#xff0c;同时还需要考虑硬件设备的兼容性和性能等因素。 初始…