分享經典的動態規劃問題(二)

2022-08-10 09:12:08 字數 4103 閱讀 1986

摘要:進一步訓練動規的基本套路.

1.正文:以前我沒有經過自省和學習,一直有誤以為動態規劃跟我們高中數學課上學的線性規劃有某種關聯,後來通過科學的敲打後逐漸明白了兩者就沒啥必然關係。若強行說它們有什麼聯絡,只能說公共點在於都是用於最優值求解上的。經典的動態規劃,很適用於計算機的計算上,一是通過大量重複的迭代操作求得收斂值就是計算機最擅長的操作,二是思路本身就帶有空間換時間的理念(線性表儲存計算結果可以復用),三是記憶體空間往往可以自行控制到最優(可以自己程式申請的記憶體空間,大小自己可控制,不像遞迴等方法直接交由系統去做申請),以下通過幾道經典例題高階訓練一下。

複習一下:

(1)題意分析;

(2)基於分析數學建模;

(3)判定是否可以符合使用動規的兩大前置條件(最優子結構和無後效性),是則下一步,否則終止(非動規可以解決的問題,另尋他法);

(4)動規基本三步曲:

1)結合題意根據模型選擇計算出比較合適的狀態轉移方程,歸約初始的狀態值,推導出終止(最終收斂)條件;

2)迭代驗證;

3)選擇合適的迭代次序實現狀態轉移方程的迭代和收斂;

(5)程式設計實現。

2.題目:

子陣列:對於給定陣列a[0..n],其中a[i..j](0<=i<=j<=n)為該陣列的子陣列.

1.最大子陣列和問題:給定陣列a[0..n]求其所有子陣列中所有元素

和最大的子陣列的元素和為多少?

2.最長公共子陣列問題:給定陣列a[0..n]和b[0..m],求兩者公共子陣列中長度最長的子陣列的長度為多少?

3.輸入輸出示例:

1.最大子陣列和問題

輸入:[-1, 2, 3, -2, 5]

輸出:8

2.最長公共子陣列問題:

輸入:[3, 2, 1, 4, 7]

[1, 2, 3, 2, 1]

輸出:3

4.例程: 

package algorithm.mathsolution;

/***

@project:

taxet

* @author:

yh*

@package:

algorithm.mathsolution

* @version:

v1.0

* @title:

分享經典的動態規劃問題(二)

* @tag:

* @description:

* 經典的子陣列類的動規問題

* 1.最大子陣列和問題

* 2.最長公共子陣列問題

* @date:

2020/6/2 23:30

*/public class subarraysolution

* (2)兩個自變數顯然要二重遍歷,考慮降維,重定義迭代子變數,考慮到可以通過歸類同一元素a[k]為末尾的子陣列為乙個子範圍的最大值來得到整個陣列的最大值,有:

* a. max[k] = max[k - 1] > 0 ? max[k - 1] + a[k] : a[k];

* b. max = max

* 邊界值推導:初始值顯然有max[i] = a[i], 終止條件為一次正向遍歷到最後的元素。

* 其中max[k]是以a[k]為末尾元素的子陣列和的最大值,各個情況互斥的子範圍得到的和最大值比較必然得到整個陣列的最大子陣列和。

* 注意的是,雖然得到兩個子方程,但可以被認為狀態轉移方程的只有第乙個,因為它才存在相鄰狀態(max[k],max[k - 1])發生轉化的過程。

* 3)校驗:[1,2,3] =>

* 根據方程a有max[0] = 1, max[1] = max[0] + a[1] = 3, max[2] = max[1] + a[2] = 6

* 根據方程b有max = 6;(本身也是乙個子陣列,符合預期結果)

* 4)程式設計實現。

* @param a*

@return

*/private static long

maxsumsubarraysum(int a)

long maxsum = 0l

;if (a.length == 0)

//構造被填的陣列

long max = new long[a.length];

//賦初始值

for (int i = 0

; i < a.length

; i++)

//迭代狀態

maxsum = max[0];

for (int i = 1

; i < max.length

; i++)

maxsum = math.max(max[i], maxsum);

}//返回結果

return maxsum;

}/**

* 2.最長公共子陣列問題

* 1)顯然也不用建模

* 2)根據題意分析出也是乙個有兩個自變數,能不能像上面那樣直接通過重定義降維?

* 答案是:不能的。

* 首先要認識到「最長」的概念當然可以應用在乙個資料結構的某種特徵資料,

* 可是「公共」就意味著至少是兩個資料結構之間的特徵資料了(當然本題只考慮兩個的情況,三個及其以上都是與此類推),

* 當然在某些都可以將兩個資料結構合併成乙個以兩者間的某種特徵資料作為陣列元素的陣列再做處理,也是一種思路,但至少這道題裡不允許,

* 因為子陣列的定義與原有陣列的強關聯,一旦不在原有的資料結構操作,尋找子陣列將會是乙個難題。

* 綜述,不能降維,否則成本會很大。

* 既然不降維,則顯然是二維的狀態轉移方程的常規尋找了。

* 繼續類似上題那樣定義max[i][j]:a[0 .. i]與b[0 .. j]的各自以a[i],b[j]為末尾元素的子陣列之間的最長公共子陣列長度。

* max[i][j]的迭代子可以有(max[i][j - 1], max[i - 1][j], max[i - 1][j - 1]),

* 可是根據題意「公共」的約束和max[i][j]的定義,max[i][j - 1],max[i - 1][j]沒有考慮意義,只與max[i - 1][j - 1],有方程:

* max[i][j] = a[i] == b[j] ? max[i - 1][j - 1] + 1 : 0;

* 3)校驗:

* 輸入:

* a: [1,2,3,2,1]

* b: [3,2,1,4,7]

* 輸出:

* 3* 抽樣,顯然max[3][1] = 2;

* max[4][2] = 3 = max[3][1] + 1

* 4)程式設計實現

* @param a*

@param b*

@return

*/private static int

maxlencommonsubarray(int a, int b)

int maxlen = 0

;if ((a.length | b.length) == 0)

int max = new int[a.length][b.length];

for (int i = 0

; i < a.length

; i++)

}maxlen = math.max(maxlen, max[i][j]);}}

return maxlen;

}public static void

mainsum(string strings) ;

system.out.println(maxsumsubarraysum(arr));

}public static void

mainlen(string strings) ;

int b = ;

system.out.println(maxlencommonsubarray(a,b));

}}

5.總結:

事實上,真正刷題的時候更應該的是發散思維去考慮更多的好解法而非只有動規的思路的,但博主希望近期就先把由淺至深的動規題都大致捋一遍再展開新方法的討論,所以對動規部分有問題可以盡早提出來。當然,要經過自己的思考再發問,之後哪怕別人也不知道或者其他情況獲取不到有效答案的,你也要自己開拓新的渠道尋找答案(博主常規解決方案),切忌自己主動放棄求知慾,不了了之。

動態規劃經典問題

from 實現在 維基百科對動態規劃的定義 動態規劃 英語 dynamic programming,簡稱dp 是一種在數學 電腦科學和經濟學中使用的,通過把原問題分解為相對簡單的子問題的方式求解複雜問題的方法。動態規劃常常適用於有重疊子問題 1 和最優子結構性質的問題,動態規劃方法所耗時間往往遠少於...

動態規劃經典問題

子串 在給定的字串中選取連續的一段 子串行 可以不連續,但是要保證出現的順序與原字串相同 比如字串abcdefg abc既是子串又是子串行 acd只是子串行 一 最大連續子串行和 給定乙個整數序列a1,a2 an。求最大的連續的子串行的和。比如的最大連續子串行的和為5 3 1 1 2 萬能列舉?每次...

動態規劃 經典問題

今天記錄下自己所學的動態規劃知識點 有三枚硬幣 2,5,7 拼成27元 最少需要幾枚硬幣 我自己理解的動態規劃實操兩部曲 第一曲 定義初始條件 第二曲 迴圈操作 以及狀態方程定義 我的第乙個動態規劃程式 題目資訊 有三枚硬幣 2,5,7 拼成27元 最少需要幾枚硬幣 看到最少 一般用動態規劃求解 1...