今天學長給我們講了區間dp,當然聽得雲裡霧裡,講完之後基本處於自閉狀態,然後還是自己到大佬的部落格,然後看部落格,但是並沒有找到很詳細的部落格,所以我想自己寫一寫,大神們勿噴哈.
一 .定義
區間dp,顧名思義是在區間上dp,它的主要思想就是先在小區間進行dp得到最優解,然後再利用小區間的最優解合併求大區間的最優解。
//一般區間
dp實現**
規定 dp[i][j] 為區間[i,j] 上的最優解
for(int
i =
1; i <= n; i++)//
區間長度為
1的初始化
dp[i][i] = x;
// x
視情況而定
for(int
len =
2; len <= n; len++)
//列舉區間長度
} 1. 石子合併
有n堆石子,現要將石子有序的合併成一堆,規定如下:每次只能移動
相鄰的2堆石子合併,合併花費為新合成的一堆石子的數量。求將這n堆石子合併成一堆的總花費最小(或最大)。
引入區間dp
區間dp的思想是 利用一次次的合併過程去更新所得的結果,以便下一次合併使用。
從小的區間一點一點分析
設 a[i] 為第i堆的石子數目 1
.若有一堆石子,無需合併 花費為 0 2
.若有兩堆石子,將這兩堆合併 花費為a[0] + a[1] 3
.若有三堆石子,有兩種情況 4
.若有四堆石子,有三種情況 ……
分析一下演算法過程
dp 二維陣列 ,橫座標代表區間起點,縱座標代表區間終點 . 比如: dp[1][2] 代表 第一堆石子到第二堆石子的最優解,下面詳細說吧,
可能這樣提前說不太理解.
首先 最外層迴圈 控制石子堆的長度(len = 2 to n)
for(int len = 2;len<=n;++len)
第二層迴圈,確定區間起點與終點
for(int i=1,j=len;j<=n;++i,++j)
經過分析還需要一層迴圈,列舉將區間分割的那個點k
for(int k = i;k最後來看這個動態轉移方程
dp[i][j] : 區間[i,j]上的石子合併最小花費
sum[i][j]: 區間[i,j] 的和
dp[i][j] = min(dp[i][j],dp[i][k]+dp[k+1][j] + sum[i][j]);
動態轉移方程可以這麼理解 現在已經將第 i 堆到第k堆 、 第k+1堆到第j堆合併了,現在只剩下這兩堆 要將這兩堆去合併
那麼就是利用之前算出來的dp[i][k] + dp[k+1][j] 再加上區間[i,j]的和
為什麼是加區間[i,j]的和呢 你把[i,k] 和[k+1,j]的石子合併到了一起
合併這兩個區間的花費一定是這兩個區間的總石子數,當然也就是[i,j]總石子數。
過程 :
1 初始化 dp陣列
過程 :
整個過程就這樣的 ,不斷的更新小區間最優解,然後最總就可以得到大區間的最優解.
鏈結 :
** :
#include #include #include #include #include #include #define d(x) for(int i = 1 ;i<=(x) ; i++)
#define init_(x) memset(x,0,sizeof(x))
#define pi acos(-1)
#define while_(x) while(scanf("%d",&x)!=eof)
#define while_c(x) while(x--)
#define scanf_(x,y) scanf("%d%d",&x,&y)
#define mst(a,b) memset((a),(b),sizeof(a))
using namespace std ;
const int inf = 1<<30 ;
typedef long long ll ;
const ll mod = 1e9+7 ;
int dp[1005][1005] ;
int sum[1005] ;
int main()
for(int len = 2 ;len<=n ; len++) // 區間長度
{ for(int i = 1 ; i<=n ; i++)// 列舉起點
{ int j = len-1+i ; // 區間終點
if(j>n)
continue; // yuejie
for(int k = 1 ; k今天先寫到這裡,等學了其他的再加補充.
區間DP入門
區間dp,看名字其實會聯想到劃分dp,其實兩者的關係並不大。劃分dp是從頭到尾劃分解決,並且有劃分數量,而區間dp沒有這些限制條件,可以從任意區間開始,一直擴大到整個區間。不斷遞推求解。同樣也是分兩步去做。首先 還是進行資料處理,比如用陣列sum i j 去儲存i到j的和,或者是用別的方式處理並儲存...
區間dp入門
區間dp就是區間上的dp,先算出小區間的最優解,再由小區間合併推出大區間的最優解。include include include includeusing namespace std const int inf 0x3f3f3f3f const int maxn 1010 int n int a m...
區間DP入門
給你乙個只含小寫字母的字串,每次只能刪除一段含有一樣字母的區間,問最少刪多少次,才能刪除整個字串 第一次做區間dp 所以記錄詳細點 適合新手 我們用dp i j 代表把區間 i 到 j 完全刪除需要的次數 狀態轉移方程 if s i s j dp i j dp i 1 j 1 1 兩頭一樣,我們把中...