斜率优化(Convex Hull Optimisation)
斜率优化(Convex Hull Optimisation)
英文直译为 凸包优化
, 指利用状态转移方程的特殊性质, 将决策转化为坐标系中的点, 维护下凸壳进行优化的技巧.
清北学堂 DP-图论营, 讲斜率优化的时候我精准睡觉, 从开始睡到结尾, 成为开学后校内测试的眼泪.
问题转化
设有一类 DP 问题, 其转移方程形如
其中, , , 单调
则可以使用斜率优化
将方程转化为函数, 变形成以 为自变量, 为因变量的函数.
这时, 函数图像是一条以 为斜率, 为截距的直线, 经过点 , 这个点被称作决策点
由于 , 只和 有关, 所以对于某一个 , 最佳决策就是使图像截距最小/大的 , 问题转化成找一个点 , 使经过它的斜率为 的直线截距最小/大
上凸 下凸
由于单调性的增减不会影响原理, 所以不失一般性, 我们假设 , , 单增, 且最优决策点使得直线截距最小
这样一来, 就有 一定在 右上出现. 斜率
分析问题的几何性质可以发现, 对于同一个 , 由于斜率一定, 所有决策点对应的直线都平行, 所有一个决策点比另一个优, 当且仅当这个点对应的直线在另一条之下; 一条线在另一条之下, 当且仅当这条线在另一条线上的一个点之下
容易发现, 如果 , 则 一定不是最优决策点, 因为如果 优于 , 说明 在直线 之上, . 又因为 , 所以 , 优于 ; 同理, 当 优于 时, 一定有 优于 .
我们把上面 这种情况称作 上凸
, 不可能是最优决策, 所以最优决策只能出现在 下凸
的情况, 即
下凸壳
维护一个单调队列, 使得在队列中的点满足 (从这时开始, 下标 特指队列中的下标), 这时候, 相邻点连成的斜率随k不断增大的折线就称作下凸壳. 下凸壳的性质是没有一个点位于其下, 在队列里的点位于下凸壳上, 不在队列里的点位于下凸壳内
容易看出, 对同一个 , 下凸壳的斜率为 的切线的切点就是最佳决策点. 没有任何决策点在切线之下, 也就没有更优的决策了.
求解
下凸壳上点 是切点, 必须满足
由于斜率 也具有单调性, 每次决策时会将其最佳决策点前面的点删掉, 所以凸包总共会被遍历一次, 每个点也只会入队一次, 因此时间复杂度是
需要注意的是, 由于新的决策点 需要入队, 所以必须在入队时保证下凸原则, 入队前删掉队尾的点 , 直到 , 将 入队
例题Luogu3195
题面大意
个物品, 大小为 , 可以选取一段连续的物品 装入容器, 容器大小为 , 大小为 的容器花费 , 是常数. 求装下所有物品的最小总费用.
状态设计
计算前缀和 表示前 件物品总大小
表示前 个物品的最小花费, 写出方程
去掉取最小值, 整理
设 , , 则
整理得
得到以 为自变量, 为因变量的函数. 因为 , 所以 , , 单调递增, 可以使用斜率优化
表示出决策点的坐标
斜率比较
代码
int main() {
n = RD();
L = RD();
sum[0] = 0;
for (register unsigned i(1); i <= n; ++i) {
a[i] = RD();
sum[i] = sum[i - 1] + a[i];
b[i] = sum[i] + i - L - 1; //处理 t[i]
c[i] = sum[i] + i; //处理 k[i]
}
f[0] = 0;
Hull[1].x = 0;
Hull[1].y = 0;
Hull[1].ad = 0; //管他有没有必要的初始化
for (register unsigned i(1); i <= n; ++i) {
while (l < r && (Hull[l + 1].y - Hull[l].y < ((b[i] * (Hull[l + 1].x - Hull[l].x)) << 1))) {
++l; //将左端过气决策点 (斜率过小) 踢出凸壳
}
f[i] = f[Hull[l].ad] + (b[i] - c[Hull[l].ad]) * (b[i] - c[Hull[l].ad]);
now.x = c[i];
now.y = c[i] * c[i] + f[i]; //转移
while (l < r && ((Hull[r].y - Hull[r - 1].y) * (now.x - Hull[r].x) > (Hull[r].x - Hull[r - 1].x) * (now.y - Hull[r].y))){
--r; //入队前维护下凸性 (单调性)
}
Hull[++r].x = now.x;
Hull[r].y = now.y;
Hull[r].ad = i; //入队
}
printf("%lld\n", f[n]);
return Wild_Donkey;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
2020-03-15 数论: 莫比乌斯反演 ( 四 ) 例题