线性规划的思想理解斜率优化DP

斜率优化DP做为1种较难理解的DP,在ACM中也有重要的作用。

现有的论文或博客讲斜率优化DP要么过于抽象,要么推倒过于繁琐,

这里用高中学的线性规划的知识来理解斜率优化DP,且思考方法具有一般性,

可用于解决各种斜率优化问题。

以hdu3507http://acm.hdu.edu.cn/showproblem.php?pid=3507为例题。

我们很容易能推出方程F【i】= min{F【j】+(Si-Sj)^2 + M }

这是1个1D/1D的方程,即状态O(N),转移O(N),直接求效率为O(N^2)。

本题N为500000,O(N^2)显然不行!

这里,用斜率优化的方法,将转移的O(N)优化为均摊复杂度O(1),总复杂度O(N)的效率解决这个问题。

首先,将方程展开,并将带有j的项整理出来:

F【i】= min{F【j】+Sj^2-2*Si*Sj+Si^2 + M }

下一步,是斜率优化的关键,即找出一个直线方程。

令K=2*Si,X=Sj,Y=F【j】+Sj^2,常数C=Si^2 + M

方程变为:

F【i】= min{Y-KX}+C

求某个F【i】,就是从前面的所有点(X,Y)的状态推来,我们开始描点。

对某个点(X,Y),它是由F【t】这个状态推来,我们称之为决策点t。

首先分析点随j的增加的趋势:j增加,可以推出X,Y都增加。

这样,我们可以把点描出来。

根据线性规划的知识,求min{Y-KX}+C,就等价于过点(X,Y)斜率为2Si的直线与y轴交点纵坐标的最小值!

下面开始优化的过程:

考虑3个决策点i,j,k(i < j < k),若Kji  > Kkj, 那么我们求解的直线无论怎么变化,j点都不可能成为最优的决策点!

只要大家拿一个尺子,用线性规划的知识动手实践一下,就会发现上面这条规律。

我们在加入新的决策点的时候,就用单调队列维护相邻的决策点的斜率递增!

也就是维护决策点的下凸性!

在求当前状态时,从队首开始,把所有相邻决策点斜率小于2Si的点删除后的第一个点,就是最小的纵坐标的值。这里,把点描出来,拿尺子一比划就出来了。


对于一般性问题,通过分析点的分布,斜率的正负等,可以推出要维护的是上凸性还是下凸性以及如何求最优解。

/*
 * p3507.cpp
 *
 *  Created on: 2013-5-30
 *      Author: zy
 */

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
const long long  INF=0xfffffffffff;
const int maxn=500010;
long long  f[maxn],s[maxn];
int a[maxn],m,n,l,r,q[maxn];
long long  min(long long x,long long y)
{
	return x<y?x:y;
}
double slope(int j,int k)
{
	if(s[j]==s[k])
	{
		if(f[j]>=f[k])return INF;
		else return -INF;
	}
	return (f[j]-f[k]+s[j]*s[j]-s[k]*s[k])/((double)s[j]-s[k]);
}
int main()
{
	while(scanf("%d%d",&n,&m)!=EOF)
	{
		memset(f,0,sizeof(f));
		memset(q,0,sizeof(q));
		s[0]=0;
		for(int i=1;i<=n;i++)
		{
			scanf("%d",&a[i]);
			s[i]=s[i-1]+a[i];
		}
		l=r=1;q[1]=0;
		for(int i=1;i<=n;i++)
		{
			while(l<r&&slope(q[l],q[l+1])<2*s[i])l++;
			f[i]=f[q[l]]+(s[i]-s[q[l]])*(s[i]-s[q[l]])+m;
			while(l<r&&slope(q[r-1],q[r])>slope(q[r],i))r--;
			r++;q[r]=i;
		}
		cout<<f[n]<<endl;
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值