今日中国金取引所の筆記試験問題をやったのですが、1問詰まってしまいました。タイトルの意味は次のとおりです。
1000元を構成するには10元、20元、50元の紙幣を使用します。組み合わせは何通りありますか?
当時、それを見て一目見て分析してみたところ、階段を上るのと同じようなナップザック問題だと思い、階段を上る再帰式をそのまま使ってみたところ、計算結果が範囲を超えていたことが分かりました。 int型。しかし、その時点ではどこにエラーがあるのかを確認していませんでした。後でテストを確認したところ、次のことがわかりました。
階段を登るという問題では、一度に 2 つのレベルを登ることができる、または一度に 1 つのレベルを登ることができる場合、[1,2] と [2,1] は 2 つの方法です。
しかし、この紙幣の問題では、30 元を補いたい場合、[10, 20] と [20, 10] の組み合わせとなり、ここで組み合わせの数が求められます。!!
そこで私は勉強するために降りてきて、それを行うには 3 つの方法があることがわかりました。
最初の最も直感的な方法は、激しく検索することです。!!
ここで、1,000元を構成するには、10元紙幣をすべて使用すると100枚必要となり、20元紙幣をすべて使用すると50枚必要となり、50元紙幣をすべて使用すると20枚必要になることがわかります。次に、 100x50x20の解空間があります。これらの可能性の中から要件を満たすものを選択するだけです。
コード
#include<iostream>
#include<vector>
using namespace std;
int main() {
int amount = 1000;
int m = 1000 / 10;
int n = 1000 / 20;
int p = 1000 / 50;
int count = 0;
for (int i = 0; i <= m; i++) {
for (int j = 0; j <= n; j++) {
for (int k = 0; k <= p; k++) {
if (i * 10 + j * 20 + k * 50 == 1000) {
count++;
}
}
}
}
cout << count << endl;
return 0;
}
上記の実装コードから、通貨価値の種類に応じてループのネスティングの層数が増加することがわかります。収集したい金額が増加すると、時間計算量も大きくなるため、そうではありません。最適なソリューション!
2 番目の方法: 動的プログラミング!
以下のブログを参照します。
アルゴリズム筆記試験問題: 1 元、5 元、10 元、20 元、50 元、100 元の額面人民元の組み合わせ x 元の問題を考慮すると、元のブログのコードが書かれているため
、 Java で記述されているので、ここでは C++ で書き直しています。動的計画法に関する具体的な議論は、すでにこのブログで詳しく述べられているので、繰り返しません~
コード
#include<iostream>
#include<vector>
using namespace std;
int main() {
vector<int> money = {
10, 20, 50 }; // 3种币值
vector<int> dp(1001, 0); // dp[i]表示利用三种币值凑成i元的组合数
dp[0] = 1; // 要凑成0元的组合数为1
for (int i = 0; i < money.size(); i++) {
// 当i=0时表示只用10元的币值凑,凑成j元有几种组合
// 当i依次增加时,表示在原来的组合数的基础上再加上用当前的币值所能凑出的组合数
for (int j = money[i]; j < dp.size(); j++) {
dp[j] += dp[j - money[i]];
}
}
cout << dp[1000] << endl;
return 0;
}
3 番目の方法は、生成関数を使用してそれを解くことです。10 元、20 元、50 元の紙幣は無数に存在するため、生成関数は次のように記述できます。
g ( x ) = ( 1 + x 10 + x 20 + x 30 + . . + x 1000 ) ⋅ ( 1 + x 20 + x 40 + . . + x 1000 ) ⋅ ( 1 + x 50 + x 100 + . . . + x 1000 ) g(x) = (1+x^{10}+x^{20}+x^{30}+...+x^{1000})\cdot(1+x) ^{20}+x^{40}+...+x^{1000})\cdot(1+x^{50}+x^{100}+...+x^{1000})g ( x )=( 1+バツ10+バツ20+バツ30+...+バツ1000)⋅( 1+バツ20+バツ40+...+バツ1000)⋅( 1+バツ50+バツ100+...+バツ1000 )
上の式の x の係数の 1000 乗を求めると、1000 元を形成する組み合わせの数になります。特定のコードは上記の生成関数を逆アセンブルする必要がありますが、実装方法がわかりません。C++ コード実装を持っている偉い人がいれば、ぜひ連絡してください。