區間DP例題總結 看似不簡單的簡單題

2021-10-08 06:30:50 字數 2960 閱讀 5620

今天,我們開始學那奇怪的區間dp。簡單來說,區間dp分為三個部分:

階段列舉左端點,再列舉右端點

策略——顧名思義就是因為有些題,需要求出中點k,但有些題卻又不需要。所以我們應該判斷,用與不用。

--------------------------------現在我們來看幾道經典例題------------------------------

n堆石子擺成一條線。現要將石子有次序地合併成一堆。規定每次只能選相鄰的2堆石子合併成新的一堆,並將新的一堆石子數記為該次合併的代價。計算將n堆石子合併成一堆的最小代價。

例如: 1 2 3 4,有不少合併方法

1 2 3 4 => 3 3 4(3) => 6 4(9) => 10(19)

1 2 3 4 => 1 5 4(5) => 1 9(14) => 10(24)

1 2 3 4 => 1 2 7(7) => 3 7(10) => 10(20)

括號裡面為總代價可以看出,第一種方法的代價最低,現在給出堆石子的數量,計算最小合併代價。

第1行:n

第2行:有n個空格分開的整數,表示n堆石子的數量

輸出最小合併代價

輸入

4

1 2 3 4

輸出

那麼這道題,是最基礎的。

考慮不在環上,而在一條鏈上的情況。

令 f[i][j[表示將區間[i,j]內的所有石子合併到一起的最大得分。

所以,狀態轉移方程就是,額~

dp[j]

[r]=

min(dp[j]

[r],dp[j]

[k]+dp[k+1]

[r]+s[r]

-s[j-1]

);

然後就沒什麼難點了,根據某些尿性,我們知道還有些坑點。

就是要賦初值為0,以及求字首和。為什麼呢?能夠更方便的計算區間和就是這麼點。那麼最核心的**呢就是:

memset

(dp,

0x3f3f3f3f

,sizeof

(dp));

for(

int i=

1;i<=n;i++

)for

(int i=

1;i<=n;i++

)for

(int len=

2;len<=n;len++

)

給出乙個長度為n的字串,每次可以刪除乙個字母相同的子串,問最少需要刪多少次。 資料規模:n <= 500

第1行:1個整數,表示字串的長度

第2行:n個字元的字串

第1行:1個整數,表示答案

5

abaca

首先,我們應該考慮割點。

設dp[i][j]表示刪去i到j的最小步數。

如果a[i]==b[j],則dp[i][j]=dp[i+1][j−1]a[i]==b[ j],則dp[i][j]=dp[i+1][j-1]a[i]==b[j],則dp[i][j]=dp[i+1][j−1]

如果a[i]!=b[j],則dp[i][j]=min(dp[i+1][j],dp[i][j−1])+1a[i]!=b[j],則dp[i][j]=min(dp[i+1][j],dp[i][j-1])+1a[i]!=b[j],則dp[i][j]=min(dp[i+1][j],dp[i][j−1])+1

然而對於資料aabb,顯然aa、bb分別為一組,但答案是3,毫無疑問,是錯的。

由此,我們就可以的到狀態轉移方程了。

dp[i][j]表示的是從i個元素到j個元素之間,刪元素用的步數最少。k呢是乙個中點。最後的目標數

dp[i]

[j]=

min(dp[i]

[j],dp[i]

[k]+dp[k]

[j]−1

) i+

1<=k<=j−1

由此可得核心**:

dp[i]

[j]=dp[i+1]

[j]+

1for

(int k=i+

1;k<=j;k++

)

#include

#include

#include

using

namespace std;

const

int maxn =

505;

char c[maxn]

;int n, m, a[maxn]

, dp[maxn]

[maxn]

;int

main()

for(

int i =

1; i <= m; i++

) dp[i]

[i]=1;

for(

int len =

2; len <= m; len++)}

}printf

("%d"

, dp[1]

[m])

;}

memset是清空陣列裡的所有東西,而初始化是把乙個陣列裡的乙個數,或幾個數賦為你想賦值的數。

但在某些因素下,這兩種用法是一樣的。

那麼引用一句話:

我個人以為,要把用迴圈來初始化變成一種常態。

簡單的區間 dp

今天我們來一起研究一下比較奇怪的區間dp 先看一道例題 石子合併 很老的題了 1960 石子合併 time limit 1 sec memory limit 128 mb submit 191 solved 78 submit status web board description 在乙個圓形操場...

lettcode 另乙個樹的子樹(不簡單的簡單題)

1 暴力 暴力解法就是針對原樹中的每乙個結點和其子樹與標定的子樹作對比,利用遞迴相當於回溯的概念 2 匹配過程中加入kmp 在匹配過程中,b數是a樹的子串的話,說明符合條件。但是針對本題來說,可能會出現以下情況 a根為1,左結點為2,右節點為null,b根為1,左結點為null,右節點為2,此時兩者...

本週學習總結(C語言的簡單例題)

1.實現數字金字塔 i 行數 j 空格數 n 金字塔的層數 include int main for a i a 1 a printf n 2.實現字母金字塔 第乙個思路和數字的類似,就是比較麻煩。include int main for a i 1 a 1 a printf n 第二個思路 直接用...