開啟章節選單
357 Let Me Count The Ways
題目連結
題目敘述
在一家大型百貨公司購物後,Mel 找零 17 分
他收到 1 枚 10 分硬幣、1 枚 5 分硬幣,以及 2 枚 1 分硬幣
當天稍晚,他又在便利商店購物,再次找零 17 分
這次他收到 2 枚 5 分硬幣和 7 枚 1 分硬幣
他開始想:「我可以在幾家商店買東西,並以不同的硬幣組合收到 17 分的找零?」經過一番腦力激盪後,他認為答案是 6
於是他挑戰你思考這個更廣泛的問題
撰寫一個程式,來計算用美國硬幣(1 分、5 分、10 分、25 分、50 分)湊出某金額的所有不同組合方式的數量
輸入格式
輸入為一組數字,每行一個,範圍為 0 到 30000(含)之間
輸出格式
對於輸入的每一個數字,輸出以下陳述中適合的一句,每行輸出一筆
變數 m 為你的程式計算出的方式數,n 為輸入的金額數值
根據方法數進行兩種格式的輸出
There are m ways to produce n cents change.
There is only 1 way to produce n cents change.
輸入說明
輸入檔案包含任意行,每一行都是一個整數,代表金額(單位為分)
輸出說明
對於輸入的每一行,輸出一行,顯示使用上述五種硬幣找零的不同方式總數
解題思路
本題可視為一維的「完全背包」或「計數型背包」
定義一維狀態 dp[x]:代表「湊出金額 x 的不同組合數」
初始:dp 全部為 1,意即「不取任何硬幣」也是一種合法方式
對於每種面額 c,透過 dp[x] += dp[x−c]
將「少一枚 c 分的湊法」累加到「當前湊法」上
固定「先處理某一面額,再處理下一面額」的步驟,能確保同一組合(例如「10+1」和「1+10」)不會被重複計算
一旦把所有面額都「加入」過一次,dp[n] 就涵蓋了以任意次數、任意組合取用這些硬幣所得的所有可能
記得要加 define int long long
程式碼
#include <bits/stdc++.h> using namespace std; #define int long long signed main() { int n; vector<int> dp(30005, 1), a = {5, 10, 25, 50}; for (auto &c : a) for (int i = c; i < 30005; i++) dp[i] += dp[i-c]; while (cin >> n) { if (dp[n] == 1) cout << "There is only 1 way to produce " << n << " cents change.\n"; else cout << "There are " << dp[n] << " ways to produce " << n << " cents change.\n"; } }