斜率优化dp讲解

对于:
d p i = m i n / m a x ( k j ∗ x i + b j ) ( 1 ≤ i ≤ n , 1 ≤ j ≤ m ) dp_i=min/max (k_j*x_i+b_j)(1\leq i\leq n ,1\leq j\leq m) dpi=min/max(kjxi+bj)(1in,1jm)
的dp方程可以通过"斜率优化"优化成 O ( m l o g m + n l o g n ) O(mlog_m+nlog_n) O(mlogm+nlogn)的。
具体如下:
可以想成在一个直角坐标系中有很多直线(也就是决策),而对于 d p i dp_i dpi就是所有直线(决策)中把 x i x_i xi带入算到的最优解。
如下图:
在这里插入图片描述
如果是 M i n Min Min的话那么最优解就构成了一个凸包的上一半(如果是 M a x Max Max就构成了一个凸包的下一半)

那怎么来构造凸包呢?怎么来查找值呢?

如果我们先考虑添加直线:
就拿 m i n min min举例吧:

如果没有直线的 k k k相等

如果一个直线的集合 S : L i n e 1 , L i n e 2 , L i n e 3 , L i n e 4 . . . . . . S:Line_1,Line_2,Line_3,Line_4...... S:Line1,Line2,Line3,Line4......依次构成了这个凸包的上半部分。
通过观察上图可以发现集合中的直线 y = k x + b y=kx+b y=kx+b的k是递减的。
如果设添加的这条直线是 l l l,集合的最后一条直线是 a a a

如果 l . k < a . k l.k<a.k l.k<a.k

则通过以下方式添加:

while(S.size()>1){
	if(a与倒数第二条函数交点的横坐标>=l与倒数第二条函数的横坐标){
		S.pop_back();
	}
}
S.push_back(l)

上面的实现是均摊 O ( 1 ) O(1) O(1)的。
这个很容易理解,可以看下图:
在这里插入图片描述
可见原来a直线的取值范围内全被更优的L取代了。

如果l.k>a.k(l不是插入到最后)

那么我们需要在集合里找到最后一条直线它的k>l.k,然后,、再一个一个考虑它后面的直线,其实和上面差不多,这样是均摊 l o g n log_n logn的。

现在讲一讲查找值

如果查询的集合是{ X 1 , X 2 , X 3 . . . X m X_1,X_2,X_3...X_m X1,X2,X3...Xm}按顺序是单调的那么就可以通过"queue"一个一个的弹出:这里用递增的查询举例:

//查找x
while(q.size()>1&&q[0].query(x)>q[1].query(x)){
	q.pop_front();
}
return q[0].query(x);

上面的实现是均摊 O ( 1 ) O(1) O(1)的。

如果无序的呢?

可以看下图的提示:

在这里插入图片描述
也就是说在这个集合里查找x对应y的最小值时,如果这个位置在 k k k那么 [ 0 , k − 1 ] [0,k-1] [0,k1]里x对应的y的值是递增的, [ k + 1 , n ] [k+1,n] [k+1,n]x对应的y的值也是递增的。
所以可以用binary_search找到这个位置k。

特殊的,如果有的k重复了,那么可以根据b来定。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值