**這裡
區間dp顧名思義就是在乙個區間上進行的一系列動態規劃。對一些經典的區間dp總結在這裡。
1) 石子歸併問題
描述:有n堆石子排成一排,每堆石子有一定的數量。現要將n堆石子並成為一堆。合併的過程只能每次將相鄰的兩堆石子堆成一堆,每次合併花費的代價為這兩堆石子的和,經過n-1次合併後成為一堆。求出總的代價最小值。
分析:要求n個石子歸併,我們根據dp的思想劃分成子問題,先求出每兩個合併的最小代價,然後每三個的最小代價,依次知道n個。
定義狀態dp [ i ] [ j ]為從第i個石子到第j個石子的合併最小代價。
那麼dp [ i ] [ j ] = min(dp [ i ] [ k ] + dp [ k+1 ] [ j ])
那麼我們就可以從小到大依次列舉讓石子合併,直到所有的石子都合併。
這個問題可以用到平行四邊形優化,用乙個s【i】【j】=k 表示區間 i---j 從k點分開才是最優的,這樣的話我們就可以優化掉一層複雜度,變為o(n^2).
**:
[cpp]view plain
copy
print?
#include
#include
#include
#define n 210
intdp[n][n],sum[n];
intmain()
memset(dp,0,sizeof
(dp));
inti,j,l,k;
for(l = 2; l <= n; ++l)
} } printf("%d\n"
, dp[1][n]);
} return
0;
}
平行四邊形優化**:
[cpp]view plain
copy
print?
#include
#include
#include
#define n 210
intdp[n][n],sum[n],s[n][n];
intmain()
memset(dp,0,sizeof
(dp));
inti,j,l,k;
for(l = 2; l <= n; ++l)
} } }
printf("%d\n"
, dp[1][n]);
} return
0;
}
2)括號匹配
poj2955,
nyoj 15
描述:給出一串的只有『(』 『)』 '[『 ']'四種括號組成的串,讓你求解需要最少新增括號數讓串中的所有括號完全匹配。
分析:我們求出這個串的最大匹配,然後串的總長度-最大匹配就是答案。
方法1:首先能想到的是轉化成lcs(最長公共子串行),列舉中間點,求所有的lcs中的最大值 * 2就是最大匹配。但是複雜度較高,光lcs一次就o(n^2)的複雜度。
方法2:
首先考慮怎麼樣定義dp讓它滿足具有通過子結構來求解、
定義dp [ i ] [ j ] 為串中第 i 個到第 j 個括號的最大匹配數目
那麼我們假如知道了 i 到 j 區間的最大匹配,那麼i+1到 j+1區間的是不是就可以很簡單的得到。
那麼 假如第 i 個和第 j 個是一對匹配的括號那麼dp [ i ] [ j ] = dp [ i+1 ] [ j-1 ] + 2 ;
那麼我們只需要從小到大列舉所有 i 和 j 中間的括號數目,然後滿足匹配就用上面式子dp,然後每次更新dp [ i ] [ j ]為最大值即可。
更新最大值的方法是列舉 i 和 j 的中間值,然後讓dp[ i ] [ j ] = max ( dp [ i ] [ j ] , dp [ i ] [ f ] + dp [ f+1 ] [ j ] ) ;
如果要求列印路徑,即輸出匹配後的括號。見詳細講解
**:
[cpp]view plain
copy
print?
#include
#include
#include
#include
using
namespace
std;
const
intn = 120;
intdp[n][n];
intmain()
} cout<}
return
0;
}
3)整數劃分問題
題目描述:給出兩個整數 n , m ,要求在 n 中加入m - 1 個乘號,將n分成m段,求出這m段的最大乘積
分析:根據區間dp的思想,我們定義dp [ i ] [ j ]為從開始到 i 中加入 j 個乘號得到的最大值。
那麼我們可以依次計算加入1----m-1個乘號的結果
而每次放入x個乘號的最大值只需列舉第x個乘號的放的位置即可
dp [ i ] [ j ] = max (dp [ i ] [ j ] , dp [ k ] [ j-1 ] * a [ k+1 ] [ i ] ) ;
**:
[cpp]view plain
copy
print?
#include
#include
#define max(a,b) a>b?a:b
long
long
a[20][20];
long
long
dp[25][25];
intmain()
} if(ok==0&&l-1==m||l-1
long
long
x,ans;
memset(dp,0,sizeof
(dp));
for(
inti=0;i
dp[i][1]=a[1][i];
ans=0;
if(m==1)
ans=dp[l-1][1];
for(
intj=2;j<=m;j++)
} } printf("%lld\n"
,dp[l-1][m]);
} return
0;
}
線性dp 區間dp
1 尼克的任務 額一道挺水的題,愣是做了幾個小時 動態規劃大致的思路還是找乙個轉移 換個詞就是影響 我們可以明顯看出本題的規則 空暇時,一遇到任務必須挑乙個接 求1 n時間內最大空暇時間 所以將任務排序是必要的,兩個關鍵字 再來想象一下當我做到第i 個任務時,我在 st i st i t i 1 時...
線狀DP及區間DP
這裡我們都用到動態規劃的思想 dynamic programming,簡稱dp。本質就是組合子問題來求解原問題,且對每個子問題只求解一次。一般來說四個步驟 1.刻畫乙個最優結構特徵 2.遞迴的定義最優解值 3.計算最優解的值 4.利用計算出的資訊構造乙個最優解 這邊直接給出 include incl...
區間dp小結
區間dp,顧名思義,就是在區間上dp,即把整個區間劃分為乙個個的小區間,在小區間內dp求出最優值,然後把這些小區間合併以後就是整個取件的最優值。下面是一些比較經典的區間dp題目 1.nyoj 737 石子合併 題意 有n堆石子,每堆有a i 個,每次合併時只能合併相鄰的兩堆,代價為兩堆石子的個數之和...