資料結構和演算法(四)動態規劃 鋼條問題

2021-09-24 04:20:43 字數 2051 閱讀 2994

一、概念

動態規劃與分治方法相似,都是通過組合子問題的解來求解原問題。分治方法將問題劃分為互不相交的子問題,遞迴求解子問題,再將它們的解組合起來,求出原問題的解。

動態規劃應用於子問題重疊情況,不同的子問題具有公共的子子問題。這種情況,分治演算法會反覆地求解公共子子問題,動態規劃演算法對每個子問題只求解一次。

動態規劃方法通常用來求解最優化問題。這類問題可以有很多可行解,我們希望尋找具有最優值的解(乙個問題可能有多個最優解)。

設計動態規劃演算法:

刻畫乙個最優解的結構特徵。

遞迴地定義最優解的值。

計算最優解的值,通常採用自底向上的方法。

利用計算出的資訊構造乙個最優解。

二、應用:鋼條切割問題:

問題描述及**

public class cut 

// r4 = max(p1 + r3, p2 + r2, p3 + r1, p4)

// 此項公式中,原問題最優解只包含乙個相關子問題(右端剩餘部分)的解,而不是兩個。

private static int cutrod(int p, int n)

int q = -1;

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

}return q;

}// t(n) 表示第二個引數值為n時,cutrod的呼叫次數

// 如何證明 t(n) = 2 ^ n 注① 下方有證明推導

// 上面的遞迴演算法之所以效率低,是因為反覆求解相同的子問題。

// 動態規劃法:安排求解順序,對每個子問題只求解一次,並將結果儲存下來。如果隨後需要子問題的解,指需查詢儲存的結果,不必反覆計算。

// 1、沿用上面的方法,加入備忘的功能 注② 此方法的執行時間 o(n^2) 下方有說明

private static int memoizedcutrod(int p, int n)

return memoizedcutrodaux(p, n, r);

}private static int memoizedcutrodaux(int p, int n, int r)

if (n == 0) else }}

r[n] = q;

return q;

}// 優化

// 注③ 此方法的執行時間 o(n^2) 下方有說明

// 這種方法一般需要恰當定義子問題「規模」的概念,使得任何子問題的求解都只依賴於「更小的」子問題的求解。

// 因此,我們將子問題按規模排序,由小到大的順序進行求解。當求解莫格仔問題時,它所依賴的更小的子問題都已

// 求解完畢,結果已經儲存。每個子問題都只需求解一次。

private static int bottomupcutrod(int p, int n)

}r[j] = q;

}return r[n];

}public static void main(string args) ;

int value = bottomupcutrod(p, 8);

system.out.println("最大價值:" + value);}}

三種方案時間複雜度分析

注①

t(n) 表示第二個引數值為n時,cutrod的呼叫次數

證明 t(n) = 2 ^ n

注②第二塊**時間複雜度 o(n^2)證明:

第一層 1 to n 還沒遞迴。這個需要執行n次。之後的遞迴 n-1,n-2,…,3,2,1

所以,時間複雜度是o(n^2)

注③第三塊**時間複雜度 o(n^2)證明:

我們可以知道,內層for的執行時間其實是乙個等差數列,

例如:n= 4 時候, 執行次數:1 + 2 + 3 + 4

n = 5 時,執行次數 1 + 2 + 3 + 4 + 5

…所以是 o(n^2)

[1] 概念及題目出處:《演算法導論》 機械工業出版社

演算法與資料結構 動態規劃

動態規劃 dp 的基本思想是 當前子問題的解可由上一子問題的解得出。動態規劃演算法通常基於由乙個遞推公式 狀態轉移方程 和若干個初始狀態 狀態 應用 1 lis longest increasing subsequence 求乙個陣列中的最長非降子串行的長度。子問題 我們可以考慮先求a 0 a 1 ...

演算法與資料結構 動態規劃

用遞迴求解問題時,反覆的巢狀會浪費記憶體。而且更重要的一點是,之前計算的結果無法有效儲存,下一次碰到同乙個問題時還需要再計算一次。例如遞迴求解 fibonacci 數列,假設求第 n 位 從 1 開始 的值,c 如下 include intfib int n return fib n 1 fib n...

資料結構與演算法練習 動態規劃

hz偶爾會拿些專業問題來忽悠那些非計算機專業的同學。今天測試組開完會後,他又發話了 在古老的一維模式識別中,常常需要計算連續子向量的最大和,當向量全為正數的時候,問題很好解決。但是,如果向量中包含負數,是否應該包含某個負數,並期望旁邊的正數會彌補它呢?例如 連續子向量的最大和為8 從第0個開始,到第...