將 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...