【二重ループ:活用編 三角形の探索】STEP: 7 お金の支払い (paizaランク C 相当) 解答例 – PHP編【二重ループメニュー】


【二重ループメニュー】 > 【二重ループ:活用編 三角形の探索】STEP: 7 お金の支払い (paizaランク C 相当)
※リンク先へ移動する為には「paiza」へのログインが必要です。

かなり難しかった印象の問題です。答えが分かった後に振り返ってみると、ただの全通りの検査問題なのですが、「最小の枚数 = 大きい金額の硬化をできるだけ使う」という先入観に捉われるとドツボにハマる問題に感じます(;^ω^)

解答例

解答方針

大きな硬貨で払えるだけ払う操作を繰り返すことで最小枚数を導けそうですが、下の例のように必ずしも「大きな硬化を使用する = 最小枚数」という事ではないことが分かります。

1 円 , 7 円 , 16 円 で 21 円を支払い

・大きな金額から支払った場合
16 円 1 枚
1 円 5 枚
・最小枚数で支払った場合
7 円 3 枚

よって全通りの硬化の支払いパターンを処理し、その中から最小の枚数を探し出します。
硬化Xの枚数を$i、硬化Yの枚数を$jとして、二重ループを回します。一円硬化の枚数は「Z – (X * $i) – (Y – $j)」で求めることができます。そして「Z + $i + $j」の値が最も小さいものを探し出す問題です。
また問題の条件、「 2 ≦ X , Y ≦ 1000」と「1 ≦ Z ≦ 3000」であることから、仮に最も大きい支払額3000円の時、最低でも2円硬化が存在することから、支払い枚数の最小値は「1500」以下であることが分かるので、ループ回数は1500回、回せばいいと考えることができます。

 

硬化の情報と支払情報を取得する

各情報を取得する部分です。「$counter」は1パターン検査した時、硬化枚数を入れておく変数です。もしこの枚数が、「$min」の値より小さかった場合、その値を「$min」に更新していくことで最小値を探っていきます。

二重ループによる全検索

二重ループ部分になります。ポイントは全検索ということで、例えばX硬化の枚数が多い時、支払額を越えてしまう場合は、0枚…つまり処理を行わないようにすることです。「X * $j」、「Y * $i」が支払額以下のときだけ、支払額から硬化の金額分を引いていき、残った金額は1円硬貨として考えることができるので、「残ったし支払額(1円硬化) + $i(Y円硬化の枚数) + $j(X円硬化の枚数) 」 = 「$counter」で硬化枚数を求めます。
あとは検証した硬化枚数が、今まで検索したものより小さかったら「$min」に代入していけば最小値を求めることができます。

エッグ

シェアする