題意:現在有n個元素的集合s。把集合s劃分成m個子集,每個子集的花費為集合中最大和最小元素的差的平方。
求如何劃分,才能總的代價最小。
思路:首先要注意到,因為集合中的元素具有無序性,我們只需知道集合中最大和最小的元素就能算出代價,也能把集合劃分出來。
所以,我們把所有元素進行排序,這樣,最小的元素和最大的元素的位置就是已知的了。
定義:dp[i][j]將前j個元素劃分成i個子集得到的最小花費和。
則: dp[
i][j
]=mi
n(dp
[i−1
][k]
+(aj
−ak+
1)2)
,i≤k
≤n初始條件 dp
[1][
j]=(
aj−a
1)2
但是這樣的複雜度是θ(
mn 2
) ,會超時。
注意到出現了平方的形式,且ai
有遞增的性質,這啟發我們可以嘗試一下是否能斜率優化。
將上面的式子變形: dp
[i][
j]=m
in(d
p[i−
1][k
]+a2
k+1−
2aja
k+1)
+a2j
假設t < k < j,如果k比t在j更優,則有 dp
[i−1
][k]
+a2k
+1−2
ajak
+1≤d
p[i−
1][t
]+a2
t+1−
2aja
t+1
變形得: (d
p[i−
1][k
]+a2
k+1)
−(dp
[i−1
][t]
+a2t
+1)a
k+1−
at+1
≤2aj
令g(t,k)
=(dp
[i−1
][k]
+a2k
+1)−
(dp[
i−1]
[t]+
a2t+
1)ak
+1−a
t+1
則 g(t
,k)≤
2aj
同樣,我們可以證明 1.g
(t,k
)≤2a
j≤2a
l,l≥
j 。 2.如果g(
t,k)
≥g(k
,j)
,k一定不是最優解。
上面的證明說明,我們能用單調佇列來優化尋找最優解的過程。
**如下:
#include
#include
#include
using namespace std;
const int maxn = 10010;
const int maxm = 5010;
int a[maxn];
int dp[maxm][maxn];
int n, m;
intq[maxn];
int head, tail;
int main()
int k = q[head];
dp[i][j] = dp[i - 1][k] + (a[j] - a[k + 1])*(a[j] - a[k + 1]);
while (head + 1
< tail)
q[tail++] = j;}}
printf("case %d: %d\n", icase, dp[m][n]);
}return
0;}
HDU 3480 DP 斜率優化
題意 給你n個數字,然後叫你從這些數字中選出m堆,使得每一堆的總和最小,一堆的總和就是這一堆中最大值減去最小值的平方,最後要使得所有堆加起來的總和最小。思路 對這些數字排序之後,很容易想到dp解法,用dp i j 表示數字i現在在第j堆,那麼轉移方程就是dp i j min dp i j dp k ...
HDU 2829 Lawrence 斜率優化DP
題意 敵人有一條直線形狀的鐵路,上面有n個據點,每個據點有對應的值表示他的價值。據點之間通過鐵路相連。整條鐵路上的戰略價值定義為 i,j 1 in ai aj,其中 i j 表示可以通過鐵路相互到達的兩個據點,ai aj 為對應據點的價值。我們現在能炸毀據點之間的鐵路,但是只能炸掉m段鐵路。希望最小...
Hdu 2993斜率優化
這題是斜率優化的入門題 數形結合在資訊學競賽中的應用中講得很好,這是其中的例二 在此標記個人理解上覺得重要的地方 首先這題求max即看成求最大斜率.include include include using namespace std typedef long long ll const int n...