1. 程式人生 > 其它 >演算法專題——區間型動態規劃

演算法專題——區間型動態規劃

演算法專題——區間型動態規劃

最近複習動態規劃,寫幾篇部落格進行總結

區間型DP特點

​ 區間型DP中的區間通常指的就是字面意義上的區間,以一組數列為例,那麼[i][j]表示的就是i到j的這個區間。

​ 區間型動態規劃的遞迴關係,通常是呈現出去頭去尾的特點,以下面的虛擬碼為例。

dp[i][j] = max(dp[i + 1][j], dp[i][j - 1]) //區間[i][j]由去掉頭(或者去掉尾)的[i + 1][j](dp[i][j - 1])推出

​ 基於此種特性,區間型DP的程式碼實現通常要對區間長度進行迴圈,即從區間長度短的迴圈到區間長度長的,當求當前狀態的值的時由於使用到的子狀態的區間長度都小於當前狀態,因此都可以推出,非常的合理且符合直覺,見下面虛擬碼。

for (int i = 1; i <= len; i++) 			//迴圈區間長度
	for (int j = 0; j <= n - len; j++) 	//迴圈做端點
		for (int z = j + 1; z < n; z++)	//迴圈右端點
			dp[i][j] = max(dp[i + 1][j], dp[i][j - 1]); //轉移方程

例題

石子合併

題面:

分析:

​ 對於成圈的東西,可以給它複製一個貼後邊,就可以變成普通的成串的序列。問題就變成了長度為2 * n的序列裡,找出長度為n的連續子序列,進行合併之後使得該序列滿足題意。

​ 不難發現(,我們可以使用dp[i][j]表示區間i到區間j可以經過合併後得到的最大分數,接著得到遞推公式(見下),同理可以求出最小的分數。

dp[i][j] = max(dp[i][k] + dp[k + 1][j]) + sum[j] - sum[i + 1]//後面的sum是字首和

小結:

​ 對於上面給出的dp的模式以及轉移方程,發現確實符合區間型動態規劃的特點,去頭去尾 + 從短長度迴圈到長長度,只要有了以上幾個共通點,程式碼就很容易得出了,這裡就不給出了

能量項鍊

題面:

分析:

​ 首先還是接環成串,發現還是合併的題目,我們仍然使用dp[i][j]表示第i顆珠子到第j顆珠子進行合併可以得到的最大值。

​ 得到遞推方程:

dp[i][j] = max(dp[i][k] + dp[k + 1][j] + a[i] * a[k + 1] * a[j + 1])//左邊珠子的值 + 右邊珠子的值 + 兩邊珠子合併之後得到的值

小結:略

248 G

題面:

分析:

​ 發現還是合併的問題,但是區間內的物體並不總是可以合併,為了方便表達我們使用dp[i][j]表達可以完全合併(最終變成一個)區間最終得到的值,最終只要取DP過程中得到的最大值即可

​ 得到遞推方程:

dp[i][j] = dp[i][k] + 1; 	if(dp[i][k] == dp[k + 1][j])

小結:略

塗色

題面:

分析:

​ 直接設狀態dp[i][j]為使區間內塗色與目標吻合的最少塗色次數,發現轉移方程就很明顯了

dp[i][j] = min(dp[i][k] + dp[k + 1][j]); //s[i] != s[j]
dp[i][j] = min(dp[i][j - 1], dp[i + 1][j]); //s[i] == s[j]

注意初始條件,即區間長度為1的時候,此時滿足dp[i][j] = 1;

小結:略