题目
好久没有碰过斜率优化了,我们从这里来开始复习一下, 先看一下题目:
从山顶上到山底下沿着一条直线种植了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
的树木全部运到我们所需要的代价,那么我们可以发现
g(i)=g(i−1)+di−1×Swi−1
那么同时我们令
f(j,i)
表示当我们第二个伐木场修建在
i
,第一个修在
j时我们可以得到的最优解我们令
cost(j,i)
表示将
j
到
i全部运到
i
我们需要的代价那么
cost(j,i)=g(i)−Sdi×Swj−1
那么我们可以得到
f(j,i)=g(j)+cost(j+1,i)+cost(i+1,n)
那么我们可以表示两个决策点,对于当前的
i
我们有两种选择方案选择第一个伐木场第一种
f(j,i)第二种
f(k,i)
如果有j的决策点优于k的决策点且
j<k
那么我们就有
f(j,i)<f(k,i)f(k,i)−f(j,i)>0[g(k)+cost(k+1,i)]−[g(j)+cost(j+1,i)]>0g(k)−g(j)+cost(k+1,i)−cost(j+1,i)>0g(k)−g(j)−Sdi×Swk+Sdi×Swj>0g(k)−g(j)>Sdi(Swk−Swj)g(k)−g(j)Swk−Swj>Sdi
这个式子我们称为斜率式那么我们就得到
i
决策点的坐标为
(Swi,g(i))那么我们可以发现当斜率满足上述的条件的时候我们的最优解就应该选择
j
节点了但是我们并不能立刻抛弃
k因为
Sdi
是单调递增的那么如果当前两点的斜率小于了我们就要将
j
扔掉,可以发现我们需要维护该队列中的保持单调递增理由如下:
维护
假设我们现在需要加入一个点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
<script type="math/tex" id="MathJax-Element-16463">k</script>无论如何都是选择不到的
队首我们需要维护一下上面的不等式,最后每一次从队首取出当前的最优决策点进行计算,最终就得到答案
(因为满足上面的性质,所以其实每一个不同情况的最优决策点也是递增的(Sd_i递增))所以我们只可能从前pop(j)而不会从前面压入任何一个使用过的节点。
代码我就先不写了