動態規劃(Dynamic Programming,簡稱DP)是一種用于解決復雜問題的算法思想,特別適用于具有重疊子問題和最優子結構性質的問題。動態規劃通過將問題分解為更小的子問題,并存儲子問題的解來避免重復計算,從而提高算法的效率。本文將介紹如何在Python中實現動態規劃,并通過幾個經典問題來展示其應用。
動態規劃的核心思想是將一個大問題分解為若干個小問題,通過解決這些小問題來逐步解決大問題。具體來說,動態規劃通常包括以下幾個步驟:
在Python中,動態規劃通常通過遞歸或迭代的方式實現。遞歸方式通常使用記憶化(Memoization)來存儲中間結果,而迭代方式則使用數組或字典來存儲狀態。
遞歸實現動態規劃時,通常使用裝飾器@lru_cache
來存儲中間結果。以下是一個計算斐波那契數列的例子:
from functools import lru_cache
@lru_cache(maxsize=None)
def fibonacci(n):
if n <= 1:
return n
return fibonacci(n-1) + fibonacci(n-2)
print(fibonacci(10)) # 輸出55
在這個例子中,@lru_cache
裝飾器會自動存儲已經計算過的斐波那契數,避免重復計算。
迭代實現動態規劃時,通常使用數組或字典來存儲狀態。以下是一個計算斐波那契數列的迭代實現:
def fibonacci(n):
if n <= 1:
return n
dp = [0] * (n + 1)
dp[0], dp[1] = 0, 1
for i in range(2, n + 1):
dp[i] = dp[i-1] + dp[i-2]
return dp[n]
print(fibonacci(10)) # 輸出55
在這個例子中,dp
數組用于存儲每個斐波那契數,通過迭代計算每個狀態的值。
背包問題是動態規劃的經典問題之一。給定一組物品,每個物品有重量和價值,要求在不超過背包容量的情況下,選擇物品使得總價值最大。
def knapsack(weights, values, capacity):
n = len(weights)
dp = [[0] * (capacity + 1) for _ in range(n + 1)]
for i in range(1, n + 1):
for w in range(1, capacity + 1):
if weights[i-1] <= w:
dp[i][w] = max(dp[i-1][w], dp[i-1][w-weights[i-1]] + values[i-1])
else:
dp[i][w] = dp[i-1][w]
return dp[n][capacity]
weights = [2, 3, 4, 5]
values = [3, 4, 5, 6]
capacity = 5
print(knapsack(weights, values, capacity)) # 輸出7
在這個例子中,dp[i][w]
表示前i
個物品在容量為w
的情況下的最大價值。
最長公共子序列(LCS)問題是另一個經典的動態規劃問題。給定兩個字符串,找出它們的最長公共子序列。
def lcs(X, Y):
m, n = len(X), len(Y)
dp = [[0] * (n + 1) for _ in range(m + 1)]
for i in range(1, m + 1):
for j in range(1, n + 1):
if X[i-1] == Y[j-1]:
dp[i][j] = dp[i-1][j-1] + 1
else:
dp[i][j] = max(dp[i-1][j], dp[i][j-1])
return dp[m][n]
X = "ABCBDAB"
Y = "BDCAB"
print(lcs(X, Y)) # 輸出4
在這個例子中,dp[i][j]
表示字符串X
的前i
個字符和字符串Y
的前j
個字符的最長公共子序列的長度。
動態規劃是一種強大的算法思想,適用于解決具有重疊子問題和最優子結構性質的問題。在Python中,動態規劃可以通過遞歸或迭代的方式實現,通常使用數組或字典來存儲中間結果。通過理解動態規劃的基本思想,并掌握其實現方法,可以有效地解決許多復雜的算法問題。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。