區間DP入門

2021-09-17 08:39:23 字數 1754 閱讀 8493

給你乙個只含小寫字母的字串,每次只能刪除一段含有一樣字母的區間,問最少刪多少次,才能刪除整個字串

(第一次做區間dp  所以記錄詳細點  適合新手)

我們用dp[ i ][ j ]代表把區間 i 到 j 完全刪除需要的次數

狀態轉移方程

if(s[ i ] == s[ j ])  dp[ i ][ j ] = dp[i+1][j-1]+1;  (兩頭一樣,我們把中間的消去,只剩下兩頭了,再消一次就好了)

if(s[ i ] != s[ j ])  dp[ i ][ j ] =min(dp[ i+1 ][ j ],dp[ i ][ j-1 ])+1;(兩頭不一樣,左端單獨消去或者右端單獨消去)

列舉區間i,j中的點,dp[ i ][ j ] = min(dp[ i ][ j ],dp[ i ][ k ] + dp[ k ][ j ] - 1);

前兩個狀態呢,比較容易得到,但是這兩個狀態只解決了一半的問題。

我們先來看如何實現這兩個狀態,首先,我們做dp,根據dp陣列的意義,

所有 i > j 的dp值為0(區間在 i < x < j )

當i = j 時,dp[ i ][ j ]=1(區間內就乙個數)

如圖 5x5

而根據剛才初步推出來的狀態轉移方程,我們知道dp[ i ][ j ]要麼等於黃色格仔+1,要麼等於兩個藍色格仔最小值+1;

所以,我們根據已知條件和狀態轉移方程就可以把dp陣列填滿

當然  我們得要斜著填 如下圖  (因為每乙個dp值是由其左下方、左邊、下邊、的值得到的)

//斜著遍歷

for(int c=1;c好,那麼這是前兩個狀態轉移,看似解決了問題,但是還有一種特殊情況沒被解決;

比如:  abaca    

根據我們的狀態轉移方程2  第乙個和第五個字元一樣,所以dp[ 1 ][ 5 ] = dp[ 2 ][ 4 ] +1=4

但是其實答案是3(用兩步消掉 b c ,一步消除所有的a)

為了解決這種狀態,我們在區間i j內列舉每乙個點為k,dp[ i ][ j ] = min(dp[ i ][ j ],dp[ i ][ k ] + dp[ k ][ j ] - 1);

正常的話dp[ i ][ j ] 是等於 dp[ i ][ k ] + dp[ k ][ j ] - 1的如  abc  或 aba

但是當 特殊情況時  如 aaa  那麼dp[ i ][ k ] + dp[ k ][ j ] - 1得到的值是小於dp[ i ][ j ]的,才是答案。

#include#include#include#includeusing namespace std;

const int maxn=1e3+7;

int dp[maxn][maxn];

char s[maxn];

int n;

int main()}}

printf("%d\n",dp[1][n]);

return 0;

}

區間DP入門

區間dp,看名字其實會聯想到劃分dp,其實兩者的關係並不大。劃分dp是從頭到尾劃分解決,並且有劃分數量,而區間dp沒有這些限制條件,可以從任意區間開始,一直擴大到整個區間。不斷遞推求解。同樣也是分兩步去做。首先 還是進行資料處理,比如用陣列sum i j 去儲存i到j的和,或者是用別的方式處理並儲存...

區間DP入門

今天學長給我們講了區間dp,當然聽得雲裡霧裡,講完之後基本處於自閉狀態,然後還是自己到大佬的部落格,然後看部落格,但是並沒有找到很詳細的部落格,所以我想自己寫一寫,大神們勿噴哈.一 定義 區間dp,顧名思義是在區間上dp,它的主要思想就是先在小區間進行dp得到最優解,然後再利用小區間的最優解合併求大...

區間dp入門

區間dp就是區間上的dp,先算出小區間的最優解,再由小區間合併推出大區間的最優解。include include include includeusing namespace std const int inf 0x3f3f3f3f const int maxn 1010 int n int a m...