题目
好久没有碰过斜率优化了,我们从这里来开始复习一下, 先看一下题目:
从山顶上到山底下沿着一条直线种植了n棵老树。当地的政府决定把他们砍下来。为了不浪费任何一棵木材,树被砍倒后要运送到锯木厂。木材只能按照一个方向运输:朝山下运。山脚下有一个锯木厂。另外两个锯木厂将新修建在山路上。你必须决定在哪里修建两个锯木厂,使得传输的费用总和最小。假定运输每公斤木材每米需要一分钱。
题目解析
定义:
wi为第i个位置上的树的重量, n为山坡的长度,di为第i棵树和第i+1棵树之间的距离,我们令Sd(i)=∑i−1j=1di(这里使用i−1)是因为第1−(i−1)为到第i棵树木距离,Sw(i)=∑ij=1wj。
首先我们先看一看这种题目我们一般是怎么处理的:g(i)表示在i处修建第一个伐木场那么要从第i−1到1的树木全部运到我们所需要的代价,那么我们可以发现
维护
假设我们现在需要加入一个点i使得队列队尾元素为j<k那么我们有如果K(j,k)>Sdi那么我们现在最优解肯定不是k那么如果我们K(k,i)<K(j,k)那么我们需要将k弹出因为这样就可以保证K(j,i)>K(k,i)那么我们j的可接受范围就更广了并且显然大于k的范围,那么这就是队尾为什么要这样维护:如果我们发现当前K(j,k)>K(k,i)那么如果K(j,k)<Sdi那么K(k,i)也会小于Sdi那么我们就可以发现k无论如何都是选择不到的
队首我们需要维护一下上面的不等式,最后每一次从队首取出当前的最优决策点进行计算,最终就得到答案
(因为满足上面的性质,所以其实每一个不同情况的最优决策点也是递增的(Sd_i递增))所以我们只可能从前pop(j)而不会从前面压入任何一个使用过的节点。
代码我就先不写了