筆記 動態規劃 之 入門與線性DP

2022-04-06 15:03:50 字數 4148 閱讀 3298

動態規劃演算法通常用於求解具有某種最優性質的問題。

那它和貪心有區別嗎?

當然有。不然叫動態規劃幹啥?

幼兒園英語老師:dp是啥?

小盆友:dog&peppa pig

英語老斯:恩恩!真聰明!

然而,你是小盆友嗎?

如果是如果不是,

dp是d****** p*******的縮寫。

意思是動態規劃。

聰明的***告訴你:是dynamic programming的縮寫!!!

我到底為什麼寫引入...

動態規劃 \((dynamic programming,簡稱 dp)\) 是一種在數學、管理科學、電腦科學、經濟學和生物資訊學中使用的,通過把原問題分解為相對簡單的子問題的方式求解複雜問題的方法。

我們需要解其不同部分(即子問題),再根據子問題的解以得出原問題的解。

通常許多子問題非常相似,為此動態規劃法試圖僅僅解決每個子問題一次,從而減少計算量:一旦某個給定子問題的解已經算出,則將其記憶化儲存,以便下次需要同乙個子問題解之時直接查表。這種做法在重複子問題的數目關於輸入的規模呈指數增長時特別有用。

可在一定程度上理解為遞推。

子問題重疊性:dp演算法把原問題視作若干個重疊子問題的逐層遞進,每個子問題的求解過程都構成乙個「階段」。在完成前乙個階段的計算後,dp才會執行下一階段的計算。

就是通常理解的由 \(i-1\) 轉化為 \(i\) 。

無後效性:為了保證dp中每一階段的計算能夠按順序、不重複的進行,dp要求已經求解的子問題不受後續階段的影響

\(\mathcal.\)

\(\text\)

摘自笨蛋花的小窩qwq

最優子結構性質:可以從子問題的最優結果推出更大規模問題的最優結果。

\(e.g.\) 假設學校有 10 個班,已經計算出了每個班的最高考試成績。那麼現在要求全校最高的成績。我們不用重新遍歷全校學生的分數進行比較,而是只要在這 10 個最高成績中取最大的就是全校的最高成績。

總結:

dp三要素:狀態、階段、決策

dp基本條件:問題重疊性、無後效性、最優子結構性質

線性動態規劃的目標函式( 即 \(f(i)\) )為特定變數( 即\(i\) )的線性函式,約束是這些變數的線性不等式或等式,目的是求目標函式的最大值或最小值(如經典的\(lis\) , \(lcs\) , \(lcis\) 等問題)。

t1 最長上公升子串行(lis)

注:子串行元素可以不相鄰。

1. \(n^2\) 做法

解析:首先,我們知道每個元素本身即為乙個上公升序列。所以我們可以考慮 \(f[i]\) 表示以第 \(i\) 個元素為結尾的最長不上公升子串行。最終結果為 \(max(f[i])\) 。狀態轉移方程為:

int len=1;//通過記錄f陣列的有效位數,求得個數

/*因為上文中所提到我們有可能要不斷向前尋找,

所以可以採用二分查詢的策略,這便是將時間複雜

度降成nlogn級別的關鍵因素。*/

for(int i=2;i<=n;i++)

f[l]=min(a[i],f[l]);//更新最小末尾 }}

cout

1. \(n^2\) 做法

解析:我們可以用 \(dp[i][j]\) 來表示第乙個串的前 \(i\) 位,第二個串的前 \(j\) 位的 \(lcs\) 的長度,那麼我們是很容易想到狀態轉移方程的:

\[f[i][j]=\beginmax(f[i][j],f[i-1][j-1]+1) \quad if\ data[i]=data[j]\\max(f[i-1][j],f[i][j-1])\end

\]#includeusing namespace std;

int dp[1001][1001],a1[2001],a2[2001],n,m;

int main()

cout<2. \(nlogn\) 做法

同樣的,上面的演算法肯定會炸...

因為洛谷此題特殊,是 \(1-n\) 的全排列,所以,我們可以通過一系列騷操作將其轉化為 \(lis\) 問題:

關於為什麼可以轉化成lcs問題,這裡提供乙個解釋。

a:3 2 1 4 5

b:1 2 3 4 5

我們不妨給它們重新標個號:把3標成a,把2標成b,把1標成c……於是變成:

a: a b c d e

b: c b a d e

這樣標號之後,lcs長度顯然不會改變。但是出現了乙個性質:

兩個序列的子串行,一定是a的子串行。而a本身就是單調遞增的。

因此這個子串行是單調遞增的。

換句話說,只要這個子串行在b中單調遞增,它就是a的子串行。

哪個最長呢?當然是b的lcs最長。

自此完成轉化。

摘自阮行止 的部落格

#include#includeusing namespace std;

int a[100001],b[100001],map[100001],f[100001];

int main()

for(int i=1;i<=n;i++)

int len=0;

f[0]=0;

for(int i=1;i<=n;i++)

f[l]=min(map[b[i]],f[l]);}}

cout

解析:本題有兩問,細節巨多,可愁壞我了...

首先,對於第一問求一套系統最多能擊落的飛彈數,很顯然我們可以求最長不上公升子串行(可模仿上述 \(lis\) 問題)。略...

其次,對於第二問求至少要多少套系統,有很多方法,你可以用最長上公升子串行、貪心等...

這裡只講貪心做法:

第二問不需要知道每次如何攔截最優,只需要知道攔截多少次。

這就像一筆畫問題,如果讓你一筆畫完成乙個圖案,你需要考慮怎麼走。但如果給你乙個一筆畫完不成的圖案,問你需要幾筆走完,你只需要數奇點的個數就可以了。

這樣做可行的原因是,所有的飛彈都要攔截,用哪個飛彈攔截系統都是一樣的,飛彈攔截系統的數目不會變。

部分**如下:

int s=0;

len2=0;

while(s0&&a[i]<=maxx) s++,maxx=a[i],a[i]=-1;

len2++;

} cout其它更多解法請點這裡

下面在講講 \(stl\) 的一些做法...

太多了,懶得寫...

\(\rrightarrow\) 點我 \(\lleftarrow\)

滾動陣列:如果在求解某一狀態時發現其只與前乙個或前幾個狀態有關,則可以利用滾動陣列來減少空間,避免mle。

由於滾動陣列會覆蓋之前的答案,所以如果只用求最終狀態則建議使用滾動陣列進行優化,若要求每乙個狀態的最優解,千萬別用!!!

若在實現狀態轉移方程時遇到決策集合(指狀態轉移方程裡的比較和選擇)只增不減的情況時,可以用乙個變數或陣列記錄,避免重複的比較,以此來降低時間複雜度。(例:lcis 問題)

刷表法與填表法:

附:可能有用的題單

排名不分先後...

動態規劃 線性dp 筆記

線性dp的經典問題 lis lcs 數字三角形。最長上公升子串行 lis 問題描述 給定乙個長度為n的數列a,求數值單調遞增的子串行的長度最長是多少。a的任意子序列可表示為b 其中k1最長公共子串行 lcs 問題描述 給定兩個長度分別為n和m的自負床a和b,求既是a的子串行又是b的子串行的字串長度最...

動態規劃 線性DP

線性dp 即線性動態規劃,不侷限於 線性時間複雜度 的一維動態規劃。與數學中的 線性空間 類似,如果乙個動態規劃演算法的 狀態 包含多個維度,但在每個維度上都具有 線性 變化的 階段 那麼該動態規劃演算法同樣稱為 線性dp 在這類問題中,需要計算的物件表現出明顯的維度以及有序性,每個狀態的求解直接構...

演算法筆記之動態規劃 DP

寫在前面 因為演算法課上駱老師講的是真的好,所以對動態規劃還是比較熟悉的。總結來說就是自底向上求解,主要在於dp轉移方程的分析,然後構造dp陣列進行填表即可,有時可能需要注意儲存求解路徑。動態規劃 簡單分析乙個最大連續子串行之和問題 給定k個整數的序列,其任意連續子串行可表示為,其中 1 i j k...