斜率优化入门

这篇具有很好参考价值的文章主要介绍了斜率优化入门。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

斜率优化是一种经典的单调队列优化类型,虽然它的名字很高大上,但是其思想内核非常简单,这篇博客就是用来帮助各位快速入门的

提示:本博客以单调队列的思想理解斜率优化

引入

dp 优化可以怎么分类?

  1. 数据结构维护决策点集的插入与查找

  2. 算法维护决策点集大小,取出无用决策点

而斜率优化 dp 属于第二者,且常常用于优化序列分割问题

Q1

P3195

A1

先列出一个朴素的 dp 方程:

\(dp_i = min(dp_j+(pre[i]+i-pre[j]-j-L-1)^2)\)

然后我们考虑决策点 \(j,k\) 满足 \(k<j\)\(j\) 优于 \(k\)

那么有:

\(dp_j + (pre[i]+i-L-1)^2 + (pre[j]+j)^2 - 2 \times (pre[i]+i-L-1) \times (pre[j]+j) < dp_k + (pre[i]+i-L-1)^2 + (pre[k]+k)^2 - 2 \times (pre[i]+i-L-1) \times (pre[k]+k)\)

\(dp_j + (pre[j]+j)^2 - 2 \times (pre[i]+i-L-1) \times (pre[j]+j) < dp_k + (pre[k]+k)^2 - 2 \times (pre[i]+i-L-1) \times (pre[k]+k)\)

\(dp_j + (pre[j]+j)^2 - dp_k + (pre[k]+k)^2 < 2 \times (pre[i]+i-L-1) \times (pre[j]+j) - 2 \times (pre[i]+i-L-1) \times (pre[k]+k)\)

\(2 \times (pre[i]+i-L-1) \times((pre[j]+j) -(pre[k]+k)) > dp_j + (pre[j]+j)^2 - dp_k + (pre[k]+k)^2\)

然后我们发现这个等式两边全部具有单调性,所以就可以用单调队列维护最优答案

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int maxn = 1e6+114;
int sum[maxn],q[maxn];
int dp[maxn];
int n,L;
int top(int j,int k){
	return (sum[j]+j)*(sum[j]+j)+dp[j]-(sum[k]+k)*(sum[k]+k)-dp[k];
}
int down(int j,int k){
	return sum[j]+j-sum[k]-k;
} 
signed main(){
	cin>>n>>L;
	for(int i=1;i<=n;i++) cin>>sum[i];
	sum[0]=dp[0]=0;
	int l=1,r=0;
	q[++r]=0;
	for(int i=1;i<=n;i++) sum[i]+=sum[i-1];
	for(int i=1;i<=n;i++){
		while(l+1<=r&&2*(i+sum[i]-1-L)*down(q[l+1],q[l])>=top(q[l+1],q[l])) l++;
		dp[i]=dp[q[l]]+(i-q[l]-1+sum[i]-sum[q[l]]-L)*(i-q[l]-1+sum[i]-sum[q[l]]-L); 
		while(l+1<=r&&top(i,q[r])*down(q[r],q[r-1])<=top(q[r],q[r-1])*down(i,q[r])) r--;
		q[++r]=i;
	}
	cout<<dp[n];
}

Q2

P3628

A2

\(dp_i=dp_j+(pre_i-pre_j)^2 \times a+(pre_i-pre_j) \times b+c\)

对于决策点 \(j,k\)\(k<j\)\(j\) 优于 \(k\)

\(dp_j+(pre_i-pre_j)^2 \times a+(pre_i-pre_j) \times b+c>dp_k+(pre_i-pre_k)^2 \times a+(pre_i-pre_k) \times b+c\)

\(dp_j+(pre_i-pre_j)^2 \times a+(pre_i-pre_j) \times b>dp_k+(pre_i-pre_k)^2 \times a+(pre_i-pre_k) \times b\)

\(dp_j+(pre_i^2+pre_j^2-2 \times pre_i \times pre_j) \times a+pre_i \times b-pre_j \times b\)

\(dp_j+a \times pre_i^2+a \times pre_j^2-2a \times pre_i \times pre_j+pre_i \times b-pre_j \times b\)

\(dp_j+a \times pre_j^2-2a \times pre_i \times pre_j-pre_j \times b>dp_k+a \times pre_k^2-2a \times pre_i \times pre_k-pre_k \times b\)

\(dp_j+a \times pre_j^2-dp_k-a \times pre_k^2+pre_k \times b-pre_j \times b>2a \times pre_i \times pre_j-2a \times pre_i \times pre_k\)

\(2a \times pre_i \times pre_j-2a \times pre_i \times pre_k<dp_j+a \times pre_j^2-dp_k-a \times pre_k^2+pre_k \times b-pre_j \times b\)

\(2a \times pre_i \times (pre_j-pre_k)<dp_j-dp_k+a \times pre_j^2-a \times pre_k^2+pre_k \times b-pre_j \times b\)

\(2a \times pre_i<(dp_j-dp_k+a \times pre_j^2-a \times pre_k^2+pre_k \times b-pre_j \times b)/(pre_j-pre_k)\)

两边同样具有单调性。

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int maxn = 1e6+114;
int sum[maxn],q[maxn];
int dp[maxn];
int n,m,a,b,c;
int top(int i,int j){
	return dp[i]-dp[j]+a*sum[i]*sum[i]-a*sum[j]*sum[j]+sum[j]*b-sum[i]*b;
}
int down(int i,int j){
	return sum[i]-sum[j];
}
signed main(){
		cin>>n;
		cin>>a>>b>>c; 
		for(int i=1;i<=n;i++) cin>>sum[i];
		sum[0]=dp[0]=0;
		int l=1,r=0;
		q[++r]=0;
		for(int i=1;i<=n;i++) sum[i]+=sum[i-1];
		for(int i=1;i<=n;i++){
			while(l+1<=r&&2*a*sum[i]*down(q[l+1],q[l])<top(q[l+1],q[l])) l++;
			dp[i]=dp[q[l]]+(sum[i]-sum[q[l]])*(sum[i]-sum[q[l]])*a+(sum[i]-sum[q[l]])*b+c; 
			//val(r,i) < val(r-1,r) r-- 
			while(l+1<=r&&top(i,q[r])*down(q[r],q[r-1])>=top(q[r],q[r-1])*down(i,q[r])) r--;
			q[++r]=i;
		}
		cout<<dp[n];
}

Q3

P2900

A3

先把所有土地按照长度排序,各位读者请自行证明排序后最优方案下总是取连续的土地,因而可以转化为序列分割类问题

\(dp_i=dp_j+ \max(j+1,i)(b_i) \times a_i\)

对于决策点 \(j,k\)\(k<j\)\(j\) 优于 \(k\)

\(dp_j+ \max(j+1,i)(b_i) \times a_i<dp_k+ \max(k+1,i)(b_i) \times a_i\)

$ \max(j+1,i)(b_i) \times a_i- \max(k+1,i)(b_i) \times a_i<dp_k-dp_j$

\(a_i \times ( \max(j+1,i)(b_i)- \max(k+1,i)(b_i))<dp_k-dp_j\)

\(a_i<(dp_k-dp_j)/( \max(j+1,i)(b_i)- \max(k+1,i)(b_i))\)

额外用一个线段树维护 \(\max\) 函数即可。

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int maxn = 1e6+114;
int q[maxn];
int dp[maxn];
struct Node{
	int a,b;
}chifan[maxn];
int tree[maxn*4];
void pushup(int cur){
	tree[cur]=max(tree[cur*2],tree[cur*2+1]); 
}
void build(int cur,int l,int r){
	if(l==r){
		tree[cur]=chifan[l].b;
		return;
	}
	int mid=(l+r)/2;
	build(cur*2,l,mid);
	build(cur*2+1,mid+1,r);
	pushup(cur);
}
int ask(int cur,int lt,int rt,int l,int r){
	if(rt<l||r<lt){
		return 0;
	}
	if(l<=lt&&rt<=r){
		return tree[cur];
	}
	int mid=(lt+rt)/2;
	int sum=0;
	sum=max(sum,ask(cur*2,lt,mid,l,r));
	sum=max(sum,ask(cur*2+1,mid+1,rt,l,r));
	return sum;
}
bool cmp(Node A,Node B){
	return A.a<B.a; 
}
int n;

int top(int j,int k){
	return dp[k]-dp[j];
}
int down(int i,int j,int k){
	return ask(1,1,n,j+1,i)-ask(1,1,n,k+1,i);
}
signed main(){
		cin>>n;
		for(int i=1;i<=n;i++) cin>>chifan[i].a>>chifan[i].b;
		sort(chifan+1,chifan+n+1,cmp);
		build(1,1,n);
		dp[0]=0;
		int l=1,r=0;
		q[++r]=0;
		for(int i=1;i<=n;i++){
			while(l+1<=r&&chifan[i].a*down(i,q[l+1],q[l])<top(q[l+1],q[l])) l++;
			dp[i]=dp[q[l]]+ask(1,1,n,q[l]+1,n)*chifan[i].a; 
			while(l+1<=r&&top(i,q[r])*down(n,q[r],q[r-1])<=top(q[r],q[r-1])*down(n,i,q[r])) r--;
			q[++r]=i;
		}
		cout<<dp[n];		
}

Q4

P2120

A4

\(dp_i=dp_j+(\sum_{k=j+1}^{i} p_k \times (x_i-x_k))+c_i\)

\(dp_i=dp_j+(\sum_{k=j+1}^{i} p_k \times x_i-p_k \times x_k)+c_i\)

\(dp_i=dp_j+(\sum_{k=j+1}^{i} p_k \times x_i)-(\sum_{k=j+1}^{i} p_k \times x_k)+c_i\)

\(dp_i=dp_j+x_i \times (\sum_{k=j+1}^{i} p_k)-(\sum_{k=j+1}^{i} p_k \times x_k)+c_i\)

令 $chifan_i=\sum_{j=1}^{i} p_j \times x_j $ 以及 \(pre_i=\sum_{j=1}^{i} p_j\)

\(dp_i=dp_j+x_i \times (pre_i-pre_j)-(chifan_i-chifan_j)+c_i\)

对于决策点 \(j,k\)\(k<j\)\(j\) 优于 \(k\)

\(dp_j+x_i \times (pre_i-pre_j)-(chifan_i-chifan_j)+c_i<dp_k+x_i \times (pre_i-pre_k)-(chifan_i-chifan_k)+c_i\)

\(dp_j-pre_j \times x_i+chifan_j<dp_k-pre_k \times x_i+chifan_k\)

\(dp_j+chifan_j-chifan_k-dp_k<pre_j \times x_i-pre_k \times x_i\)

\(x_i \times (pre_j-pre_k)>(dp_j-dp_k+chifan_j-chifan_k)\)

\(x_i>(dp_j-dp_k+chifan_j-chifan_k)/(pre_j-pre_k)\)

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int maxn = 1e6+114;
int sum[maxn],q[maxn];
int chifan[maxn],c[maxn],p[maxn],x[maxn];
int dp[maxn];
int n,m;
int top(int j,int k){
	return dp[j]-dp[k]+chifan[j]-chifan[k];
}
int down(int j,int k){
	return sum[j]-sum[k];
}
void init(){
	for(int i=1;i<=n;i++){
		sum[i]=sum[i-1]+p[i]; 
	}
	for(int i=1;i<=n;i++){
		chifan[i]=chifan[i-1]+p[i]*x[i];
	}
} 
signed main(){
		cin>>n;
		for(int i=1;i<=n;i++) cin>>x[i]>>p[i]>>c[i];
		init();
		dp[0]=0;
		int l=1,r=0;
		q[++r]=0;
		for(int i=1;i<=n;i++){
			while(l+1<=r&&x[i]*down(q[l+1],q[l])>top(q[l+1],q[l])) l++;
			dp[i]=dp[q[l]]+x[i]*(sum[i]-sum[q[l]])-(chifan[i]-chifan[q[l]])+c[i];
			while(l+1<=r&&top(i,q[r])*down(q[r],q[r-1])<=top(q[r],q[r-1])*down(i,q[r])) r--;
			q[++r]=i;
		}
		if(p[n]==0) dp[n]-=c[n];
		cout<<dp[n];
		return 0;
}

总结

一般来说,为了兼顾单调性以及不被贪心暴踩,斜率优化 dp 带有一个平方项

不过只要对于决策点 \(j,k\)\(k<j\) 能表述成 \(f(i) > g(j,k)\) (\(g(j,k)\) 常常为斜率的形式,因此叫做斜率优化)且两边单调的形式,都可以斜率优化,不过有时候这个式子更为灵活,需要变通文章来源地址https://www.toymoban.com/news/detail-409885.html

到了这里,关于斜率优化入门的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 《Git入门实践教程》前言+目录

    版本控制系统(VCS)在项目开发中异常重要,但和在校大学生的交流中知道,这个重要方向并未受到重视。具备这一技能,既是项目开发能力的体现,也可为各种面试加码。在学习体验后知道,Git多样化平台、多种操作方式、丰富的资源为业内人士提供了方便的同时,也造成

    2024年02月10日
    浏览(74)
  • Webpack5入门到原理1:前言

    开发时,我们会使用框架(React、Vue),ES6 模块化语法,Less/Sass 等 css 预处理器等语法进行开发。 这样的代码要想在浏览器运行必须经过编译成浏览器能识别的 JS、Css 等语法,才能运行。 所以我们需要打包工具帮我们做完这些事。 除此之外,打包工具还能压缩代码、做兼容

    2024年01月20日
    浏览(51)
  • 人工智能:一种现代的方法 第三章 经典搜索 上

    3.1 问题求解智能体 环境假设:单Agent、确定的、可观察的、离散的、已知的 问题求解智能体的工作流程通常如下: 目标设定 :首先,问题求解智能体需要有一个明确的目标或需要解决的问题。 问题形式化 :然后,智能体需要将这个目标或问题形式化为一个搜索问题。这通

    2024年02月05日
    浏览(51)
  • 一种KV存储的GC优化实践

    作者:vivo 互联网服务器团队- Yuan Jian Wei 从内部需求出发,我们基于TiKV设计了一款兼容Redis的KV存储。基于TiKV的数据存储机制,对于窗口数据的处理以及过期数据的GC问题却成为一个难题。本文希望基于从KV存储的设计开始讲解,到GC设计的逐层优化的过程,从问题的存在到不

    2024年02月04日
    浏览(64)
  • FQS:一种神奇的数仓查询优化技术

    本文分享自华为云社区《根据执行计划优化SQL【绽放吧!GaussDB(DWS)云原生数仓】》,作者:西岭雪山。 如果您刚接触DWS那一定会好奇想要知道\\\"REMOTE_FQS_QUERY\\\" 到底代表什么意思?我们看官网的描述是代表这执行计划已经CN直接将原语句下发到DN,各DN单独执行,并将执行结果在

    2024年02月05日
    浏览(41)
  • 一种具有轨迹优化的无人驾驶车实时运动规划器 论文阅读

    论文题目:A Real-Time Motion Planner with Trajectory Optimization for Autonomous Vehicles Abstract 本文的实时规划器首先将空间离散化,然后基于一组成本函数搜索出最佳轨迹。迭代优化所得到的轨迹的Path和Speed。 post-optimization计算复杂度低,能够在几次迭代内收敛到一个更高质量的解,该框

    2024年01月17日
    浏览(56)
  • 论文阅读笔记 — 第2篇 — 一种基于Epsilon支配的多目标优化问题档案导向均衡优化器

    同上一篇笔记。 论文阅读笔记 — 第1篇 — 一种具有全局优化策略的增强MSIQDE算法-CSDN博客 这一篇论文同样也属于群智能优化领域,主要研究其Abstarct和introduction以及论文结构,具体算法细节不深入探讨(群智能优化算法总体思路大都差不多)。如有兴趣或者需要用到该算法

    2024年01月22日
    浏览(49)
  • 深度学习论文解读分享之diffGrad:一种卷积神经网络优化方法

    diffGrad: An Optimization Method for Convolutional Neural Networks Shiv Ram Dubey , Member, IEEE, Soumendu Chakraborty , Swalpa Kumar Roy , Student Member, IEEE, Snehasis Mukherjee, Member, IEEE, Satish Kumar Singh, Senior Member, IEEE, and Bidyut Baran Chaudhuri, Life Fellow, IEEE Adaptive moment estimation (Adam), difference of gradient, gradient descent,

    2024年01月17日
    浏览(53)
  • 【群智能算法改进】一种改进的白鲸优化算法 改进白鲸优化算法 改进后的EBWO[1]算法【Matlab代码#40】

    白鲸优化算法 (BWO,beluga whale optimization) 是2022 年在白鲸游泳、捕鲸及跌倒等行为中得到启发而提出的一种新型基于种群的元启发式算法。BWO 主要对白鲸游泳、捕食及跌倒 (坠落) 等行为进行模拟,其对应探索、开发及鲸鱼坠落三个阶段。BWO 当中鲸落概率与平衡因子均为自适应

    2024年02月09日
    浏览(46)
  • 【群智能算法改进】一种改进的白鲸优化算法 改进白鲸优化算法 改进后的EBWO[2]算法【Matlab代码#42】

    白鲸优化算法 (BWO,beluga whale optimization) 是2022 年在白鲸游泳、捕鲸及跌倒等行为中得到启发而提出的一种新型基于种群的元启发式算法。BWO 主要对白鲸游泳、捕食及跌倒 (坠落) 等行为进行模拟,其对应探索、开发及鲸鱼坠落三个阶段。BWO 当中鲸落概率与平衡因子均为自适应

    2024年02月12日
    浏览(37)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包