動態規劃之硬幣找零問題

2022-01-11 14:15:56 字數 1680 閱讀 5331

將 n 個硬幣按照面值進行排序, 使得:

\[c_1 < c_2 < ... < c_n

\]\(s \leftarrow \empty\)

while x > 0

k \(\leftarrow\) largest coin denomination \(c_k\) such that \(c_k \leq x\)(最大硬幣面值 \(c_k\) 使得 \(c_k \leq x\))

if no such k, return "no solution"

else

\(x \leftarrow x - c_k\)

\(s \leftarrow s \ \cup \ \\)

return s

這個貪婪演算法 -- 收銀員演算法是最優的嗎?

定理

收銀員演算法對於美國硬幣來說是最佳的演算法, 即這個貪婪演算法可以求出最優解(u.s. coins -- 1, 5, 10, 25, 100).

可以根據 x 進行歸納證明(存疑, 待補充, 演算法本身肯定是正確的).

在某些情況下, 甚至可能無法找到可行的解決方案

問題的關鍵是: 我們不知道 x 的值

我們將嘗試所有可能的 \(x\) 值, 並取最小值

\[c[n] = \left\

min_\left\ \qquad if \ n > 0 & \\

0 \qquad \qquad \qquad \qquad \qquad \qquad \ if \ n = 0& \\

\end\right.

\]偽碼描述

這棵樹的根節點是我們要求解的 n, 然後 n 分別減去 \(d_1, d_2, d_3\) 得到其三個子節點, 然後從左到右依次遞迴分解這 3 個子節點, 然後以此類推.

最後求解出來的找零所需的最少的硬幣的數目是 4, 根據上面的樹可以發現, 具體的分法不是唯一的.

dp 用於解決具有以下特徵的問題:

可以修改遞迴演算法以使用記憶化

change()有許多重複的工作, 使用乙個表來使得演算法的時間複雜度變為 \(o(nk)\)

偽碼描述

int dp_change(int n)

return tmp; // 最後返回的即 c[n]

}

這個演算法和上面的遞迴相反, 是從底向上進行構建的.n0

1234

5678

9101112

\(c[n]\)01

2123

2123

234\(d_1\)01

2012

0012

012\(d_2\)00

0111

2000

111\(d_3\)00

0000

0111

111自下而上, 建立一張已解決的子問題表, 用於解決較大的子問題

貪婪演算法是自上而下的, 動態規劃可能是過大的(overkill); 貪婪演算法往往更容易編碼.

硬幣找零問題之動態規劃

今天我們看一下動態規劃的硬幣找零問題,主要通過一系列程式設計題分析動態規劃的規律,只要掌握這一規律,許多動態規劃的相關問題都可以模擬得到。題目1 給定陣列arr,arr中所有的值都是正數且不重複。每個值代表一種面值的貨幣,每種面值的貨幣可以使用任意張,再給定乙個整數aim代表要找的錢數,求組成aim...

硬幣找零問題(動態規劃)

給定指定的硬幣種類,面值為 1,3,5 在此具體化些 給定所找零的錢數 sum,給出最少的硬幣找零數,每個種類的硬幣無限使用。看到這問題,當時我想到用貪心演算法來求解,最後求解方案因為巧合對了,後來在網上看到動態規劃的題目,才知道貪心演算法得不到最優解,比如 給定 面值為 1,3,4,給定找零數為 ...

硬幣找零問題 動態規劃問題

看到了 這文章,由於我不太懂他的 所以我按他的題和思路,寫了 思路我就不寫了,就是動態規劃的思路,先保證區域性最優,再慢慢向全區域性最優 include include include include using namespace std const int m 100 int coinsum m...