演算法導論 斜率優化

2022-05-19 21:57:54 字數 3094 閱讀 8647

【題意】

給出n條連續線段,每條線段都有長度為x[i],我們可以把連續若干條線段連在一起,變成乙個組合,兩條線段如果相連,就要在兩條線段中間新增乙個長度為1的格仔(如果沒有相連就不用新增),假如我們現在選擇把第i條到第j條線段之間的所有線段變成一組合的話,這個組合的總長度就為:x[i]+x[i+1]+x[i+2]+x[i+3]+...+x[j]+j-i,現在給出乙個常數l,假設當前選擇的組合的長度為s,那麼這個組合就為我們產生了(s-l)^2的費用,求出把n條線段分成若干組合所需要的最小費用,單獨的線段可以成為乙個組合

【輸入檔案】

第一行兩個整數,分別為n和l。

下來n個數字xi,按編號從小到大輸入每個物品的容量。

1<=n<=50000,1<=l,xi<=10^7

【輸出檔案】

乙個整數,總花費的最小值。

【樣例輸入】

5 43 4 2 1 4

【樣例輸出】

1斜率優化其實就是乙個用來優化dp的演算法,但必須當dp方程具有單調性的時候才能使用

下來我們用例題來說明斜率優化

f[i]表示1~i的最小花費。

f[i]=min(f[j]+(sum[i]-sum[j]+i-(j+1)-l)^2) (j

首先我們先來證明決策單調性

假設j1

即要滿足:f[j2]+(s[i]-s[j2]-l)^2

則對於i後的所有狀態t,是否j2也不比就j1差?(術語:證明決策單調性)

即f[j2]+(s[t]-s[j2]-l)^2 < f[j1]+(s[t]-s[j1]-l)^2

容易理解s[t]=s[i]+v

所以得到(1)不等式:f[j2]+(s[i]-s[j2]-l+v)^2

因為已知(2)不等式:f[j2]+(s[i]-s[j2]-l)^2

所以化簡(1)不等式:把s[i]-s[j2]-l看成乙個整體,v看成乙個整體,得到:

f[j2]+(s[i]-s[j2]-l)^2+2*v*(s[i]-s[j2]-l)+v^2

比較(2)不等式:

左邊多了一部分:2*v*(s[i]-s[j2]-l)+v^2

右邊多了一部分:2*v*(s[i]-s[j1]-l)+v^2

所以我們只需要證:

2*v*(s[i]-s[j2]-l)+v^2<=2*v*(s[i]-s[j1]-l)+v^2

即:(s[i]-s[j2]-l)<=(s[i]-s[j1]-l)

即: -s[j2] <= -s[j1]

即:s[j1]

總結:對於當前i:j2比j1好,那麼對於t(i

所以當前i選擇j2,淘汰j1,以後的t也不會在j2存在的時候選擇j1

所以i的時候就可以永久淘汰j1

然後來求斜率方程

因為f[j2]+(s[i]-s[j2]-l)^2<=f[j1]+(s[i]-s[j1]-l)^2

展開:f[j2]+(s[i]-l)^2-2*(s[i]-l)*s[j2]+s[j2]^2<=f[j1]+(s[i]-l)^2-2*(s[i]-l)*s[j1]+s[j1]^2

即f[j2]-2*(s[i]-l)*s[j2]+s[j2]^2<=f[j1]-2*(s[i]-l)*s[j1]+s[j1]^2

即f[j2]+s[j2]^2-2*(s[i]-l)*s[j2]<=f[j1]+s[j1]^2-2*(s[i]-l)*s[j1]

即[(f[j2]+s[j2]^2)-(f[j1]+s[j1]^2)]<=2*(s[i]-l)*s[j2]-2*(s[i]-l)*s[j1]

即[(f[j2]+s[j2]^2)-(f[j1]+s[j1]^2)]/(s[j2]-s[j1])<=2*(s[i]-l)

對於j來說:

製造的點座標

y=f[j]+s[j]^2

x=s[j]

我們用佇列list在存有意義的決策點,list中相鄰兩點的斜率遞增(佇列中的點形成乙個下凸殼),而且都大於2*(s[i]-l),那麼佇列頭對於i來說就是最優決策點

加入決策i時,令隊尾為list[tail],前乙個為list[tail-1]

斜率函式slop(點1,點2)

滿足:slop(list[tail-1],list[tail])>slop(list[tail],i)時,

那麼隊尾list[tail]在三者(list[tail-1],list[tail],i)對於未來的tail絕對不會是最優的策略,所以將其彈出tail--

最後遇到了:slop(list[tail-1],list[tail])

然後f[n]就是答案了

#include#include

#include

#include

using

namespace

std;

typedef

long

long

ll;ll a[

51000],s[51000],f[51000

];/*

f[i]=min(f[j]+(sum[i]-sum[j]+i-j-1-l)^2)

f[i]=min(f[j]+(s[i]-s[j]-l)^2)

f[j2]+(s[i]-s[j2]-l)^2<=f[j1]+(s[i]-s[j1]-l)^2

f[j2]+(s[i]-l)^2-2*s[j2]*(s[i]-l)+s[j2]^2<=f[j1]+(s[i]-l)^2-2*s[j1]*(s[i]-l)+s[j1]^2

f[j2]+s[j2]^2-2*s[j2]*(s[i]-l)<=f[j1]+s[j1]^2-2*s[j1]*(s[i]-l)

f[j2]-f[j1]+s[j2]^2-s[j1]^2<=2*s[j2]*(s[i]-l)-2*s[j1]*(s[i]-l)

f[j2]-f[j1]+s[j2]^2-s[j1]^2<=2*s[j2]*(s[i]-l)-2*s[j1]*(s[i]-l)

(f[j2]-f[j1]+s[j2]^2-s[j1]^2)/(s[j2]-s[j1])<=2*(s[i]-l)

*/double slop(int j1,int

j2)int list[51000];int

head,tail;

intmain()

printf(

"%lld\n

",f[n]);

return0;

}

演算法 動態規劃之斜率優化

斜率優化通常使用單調佇列輔助進行實現,用於優化 dp 的時間複雜度。使用單調佇列優化 dp 通常可以解決型如 dp i min f j g i 的狀態轉移方程。其中 f i 是只關於 i 的函式,g j 是只關於 j 的函式。樸素的解決方法是在第二層迴圈中列舉 j 來實現最小值,時間複雜度為 o n...

Dp優化 斜率優化

該模板的ai要具有單調性,也就是sum陣列 若沒有單調性,加個二分即可 我的一篇題解,很詳細 1 寫出狀態轉移方程 2 按照斜率優化的式子推導出式子 3 代入模板即可。include include using namespace std typedef long long ll const int...

演算法導論 快速排序優化演算法!

常見快速排序 時間複雜度最好情況下o nlgn 最壞情況o n2 快速排序是基於分治模式的 分解 陣列a p.r 被劃分成兩個 可能空 子陣列a p.q 1 和a q 1.r 使得a p.q 1 中的每個元素都小於等於a q 而且,小於等於a q 1.r 中的元素。下 標q 也在返個劃分過程中迕行計...