題目
好久沒有碰過斜率優化了,我們從這裏來開始複習一下, 先看一下題目:
從山頂上到山底下沿着一條直線種植了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 無論如何都是選擇不到的
隊首我們需要維護一下上面的不等式,最後每一次從隊首取出當前的最優決策點進行計算,最終就得到答案
(因爲滿足上面的性質,所以其實每一個不同情況的最優決策點也是遞增的(Sd_i遞增))所以我們只可能從前pop(j)而不會從前面壓入任何一個使用過的節點。
代碼我就先不寫了