uestc oj 1685 我要長高

2021-06-14 17:06:17 字數 4087 閱讀 2763

這是一道動態規劃的dp問題

但是明顯需要o(n^3)的時間複雜度  ,顯然需要進行優化,

並且有明顯的可以進行單調佇列優化的特徵,在本次確定高度之後,

總能在前一次當中尋找到乙個最優解。

最優解當然是由上一次的積累量+本次積累量(其中上一次的積累量與本次的積累量之間無關聯)

就是說dp[i-1][k]的積累量只是與k有關  dp[i][j]的積累量至於j有關

由本次狀態轉移方程

dp[i][j]=min(dp[i-1][k] + abs(j-k)*c + (x[i]-j)*(x[i]-j));其中x[i]是第i個兒子原本的身高

通過分解滿足條件

下面摘抄一位大牛的部落格

單調佇列是一種嚴格單調的佇列,可以單調遞增,也可以單調遞減。隊首位置儲存的是最優解,第二個位置儲存的是次優解,ect。。。

單調佇列可以有兩個操作:

1、插入乙個新的元素,該元素從隊尾開始向隊首進行搜尋,找到合適的位置插入之,如果該位置原本有元素,則替換它。

2、在過程中從隊首刪除不符合當前要求的元素。

單調佇列實現起來可簡單,可複雜。簡單的乙個陣列,乙個head,乙個tail指標就搞定。複雜的用雙向鍊錶實現。

用處:1、儲存最優解,次優解,ect。

2、利用單調佇列對dp方程進行優化,可將o(n)複雜度降至o(1)。也就是說,將原本會超時的n維dp降優化至n-1維,以求通過。這也是我想記錄的重點

是不是任何dp都可以利用單調佇列進行優化呢?答案是否定的。

記住!只有形如 dp[i]=max/min (f[k]) + g[i]  (k優化的物件就是f[k]。

通過例題來加深感受

我要長高

韓父有n個兒子,分別是韓一,韓二…韓n。由於韓家演技功底深厚,加上他們間的密切配合,演出獲得了巨大成功,票房甚至高達2000萬。舟子是名很有威望的公知,可是他表面上兩袖清風實則內心陰暗,看到韓家紅紅火火,嫉妒心遂起,便發微薄調侃韓二們站成一列時身高參差不齊。由於舟子的影響力,隨口一句便會造成韓家的巨大損失,具體虧損是這樣計算的,韓一,韓二…韓n站成一排,損失即為c*(韓i與韓i+1的高度差(1<=i有若干組資料,一直處理到檔案結束。 每組資料第一行為兩個整數:韓子數量n(1<=n<=50000)和舟子係數c(1<=c<=100) 接下來n行分別是韓i的高度(1<=hi<=100)。

首先建立方程,很容易想到的是,dp[i][j]表示第 i 個兒子身高為 j 的最低花費。分析題目很容易知道,當前兒子的身高花費只由前乙個兒子影響。因此,

dp[i][j]=min(dp[i-1][k] + abs(j-k)*c + (x[i]-j)*(x[i]-j));其中x[i]是第i個兒子原本的身高

我們分析一下複雜度。

首先有n個兒子,這需要乙個迴圈。再者,每個兒子有0到100的身高,這也需要一維。再再者,0到100的每乙個身高都可以有前一位兒子的身高0到100遞推而來。

所以樸素演算法的時間複雜度是o(n^3)。題目只給兩秒,難以接受!

分析方程:

當第 i 個兒子的身高比第 i-1 個兒子的身高要高時,

dp[i][j]=min(dp[i-1][k] + j*c-k*c + x);   ( k<=j ) 其中 x=(x[i]-j)*(x[i]-j)。

當第 i 個兒子的身高比第 i-1 個兒子的身高要矮時,

dp[i][j]=min(dp[i-1][k] - j*c+k*c + x);   ( k>=j )

對第乙個個方程,我們令 f[i-1][k]=dp[i-1][k]-k*c,  g[i][j]=j*c+x; 於是 dp[i][j] = min (f[i-1][k])+ g[i][j]。轉化成這樣的形式,我們就可以用單調佇列進行優化了。

第二個方程同理。

接下來便是如何實現,實現起來有點技巧。具體見下

1 #include2 #include

3 #include4 #include5

using

namespace

std;

6#define inf 0xfffffff

7#define min(a,b) a8

#define max(a,b) a>b?a:b910

int dp[2][101

];11

intn,c;

12int q[101

];13

inthead,tail,cur;

1415

intmain()

1644

//比前乙個人矮

45 head=tail=0

; 46

for(j=100;j>=0;j--) //

當身高為j時候,佇列裡便已經儲存了100~j+1的資訊,正寫反寫是有技巧的

4755}56

int ans=inf;

57for(i=0;i<=100;i++)

58 ans=min(ans,dp[cur][i]);

59 printf("

%d\n

",ans);60}

61return0;

62 }

下面是我重寫的**感觸頗多

#include#define inf 0xfffffff

int n,c,flag,a,i,j,front,rear,temp;

int que[100];

int dp[2][110];//用於記錄最優解只儲存最後結果

int main()}}

int ans = inf;

for(i=0;i<=100;i++)

printf("%d\n",ans);

}return 0;

}

首先是在inf的訪問上來說,一開始把7個f看成了8個f造成了不理解,明明是取乙個很大的值,怎麼變成了乙個-1呢?

隨後自己取了0x7fffffff這個值,結果出現了錯誤,原因是在過程中會進行加法,這個最大的int整形,加上乙個數字之後就變成了

負數了。於是就得出了十分錯誤的結果。

還有就是在起初初始化的時候對小於a的值進行inf賦值是很有必要性的,因為其實每個值都會用得上的,都會進行計算入隊的

我們只是取得最小值(符合條件的)

下面這個解法是我從另乙個部落格摘取的 效率更高

其實我們根本沒有必要去維護乙個佇列,其實只需要要在高於或者矮於的情況下的最小值就行了,於是乎在

佇列維護的時候只是需要一次最小值比較就行了

還有在高於前乙個人的情況下只是需要從h【i-1】開始列舉到mlen就行了

在矮於前乙個人的身高的時候  只需要從mlen 到 h【i】列舉就行了

很好吧

#include #include #include #include #define inf 0x3fffffff

#define maxn 50005

using namespace std;

int n, m, h[maxn], dp[maxn][105];

// dp[i][j] 第i個人身高為j時的最少代價

// 當前面的身高小於其身高時

// dp[i][j] = min( dp[i-1][k] + mj - mk + (j - h[i])^2 )同理

// 對於上面的式子我們只需要維護好上一次狀態的 dp[i-1][k]-mk 的最小值就可以了

// dp[i][j] = min( dp[i-1][k] + mk - mj + (j - h[i])^2 );

// 對於上面的式子我們只需要維護好上一次狀態的 dp[i-1][k]+mk 的最小值就可以了

int main()

for (int i = 0; i <= n; ++i)

for (int i = h[1]; i <= lim; ++i)

for (int i = 2; i <= n; ++i)

}min = inf;

for (int j = lim; j >= h[i]; --j) }}

min = inf;

for (int i = h[n]; i <= lim; ++i)

printf("%d\n", min);

}return 0;

}

UESTC 1685 我要長高

單調佇列優化dp。借鑑 首先建立方程,很容易想到的是,dp i j 表示第 i 個兒子身高為 j 的最低花費。分析題目很容易知道,當前兒子的身高花費只由前乙個兒子影響。因此,dp i j min dp i 1 k abs j k c x i j x i j 其中x i 是第i個兒子原本的身高 我們分...

UESTC 我要長高

題意是 就是題目描述的那樣了吧 題意很顯而易見,一眼dp題 dp i j 代表第i個人身高為j時的最小消耗,dp i j min dp i 1 k abs j k c j h i 2 複雜度o n h i 2 很明顯有點大,學習了一下單調佇列優化dp之後,發現形如dp i min max dp j ...

UESTC 我要長高 DP優化

韓父有n個兒子,分別是韓一,韓二 韓n。由於韓家演技功底深厚,加上他們間的密切配合,演出獲得了巨大成功,票房甚至高達2000萬。舟子是名很有威望的公知,可是他表面上兩袖清風實則內心陰暗,看到韓家紅紅火火,嫉妒心遂起,便發微薄調侃韓二們站成一列時身高參差不齊。由於舟子的影響力,隨口一句便會造成韓家的巨...