mirror of
https://github.com/krahets/hello-algo.git
synced 2026-07-22 19:36:06 +00:00
90 lines
6.1 KiB
Markdown
90 lines
6.1 KiB
Markdown
---
|
||
comments: true
|
||
---
|
||
|
||
<!-- utils/exercises/publish_exercises.py により自動生成されています。直接編集しないでください。 -->
|
||
|
||
# 15.6 演習
|
||
|
||
## 15.6.1 確認問題
|
||
|
||
### 1. 毎回最大の硬貨を選べば必ず最善か
|
||
|
||
硬貨の額面は `[1, 7, 10]`、目標金額は 14 です。
|
||
|
||
<!-- numbered-subquestions -->
|
||
|
||
1. 「残りの金額を超えない最大の額面を毎回選ぶ」という方法を使い、選ぶ硬貨を書いてください。
|
||
2. より少ない硬貨を使う方法はありますか?ある場合は 1 つ書き、ない場合は理由を説明してください。
|
||
3. この結果から、この貪欲戦略がどのような硬貨の額面でも正しいといえますか?
|
||
|
||
??? success "解答"
|
||
|
||
1. 貪欲戦略では `10 + 1 + 1 + 1 + 1` の順に選び、硬貨は合計 5 枚です。
|
||
|
||
2. より少ない硬貨を使う方法があります。`7 + 7` なら、硬貨は 2 枚だけです。
|
||
|
||
3. 正しいとはいえません。この反例から、どのような硬貨の額面でも、現在選べる最大の額面を毎回選ぶ方法が最小の硬貨枚数を得るとは限らないと分かります。
|
||
目の前で最大の選択をすると、その後のよりよい組合せを作れなくなる場合があります。
|
||
|
||
### 2. ナップサックに先に入れる品物
|
||
|
||
容量 4 キログラムのナップサックに、次の品物を入れます。品物の一部だけを入れることもでき、
|
||
得られる価値は入れた重さに比例します。
|
||
|
||
- 品物 A:重さ 4 キログラム、価値 20。
|
||
- 品物 B:重さ 3 キログラム、価値 18。
|
||
|
||
<!-- numbered-subquestions -->
|
||
|
||
1. 2 つの品物の 1 キログラム当たりの価値は、それぞれいくつですか?どちらを先に入れるべきですか?
|
||
2. 分数ナップサックの貪欲戦略に従ってナップサックを満たすと、最終的な価値はいくつですか?
|
||
3. 品物を分割でき、ナップサックに総重量の制限がある場合、品物を選ぶときに比較すべきなのは、総価値と 1 キログラム当たりの価値のどちらですか?その理由も説明してください。
|
||
|
||
??? success "解答"
|
||
|
||
1. A の 1 キログラム当たりの価値は `20 ÷ 4 = 5`、B は `18 ÷ 3 = 6` です。
|
||
したがって、単位重量当たりの価値が高い B を先に入れます。
|
||
|
||
2. まず B をすべて入れ、3 キログラムを使って価値 18 を得ます。残りの容量は 1 キログラムなので、
|
||
次に A を 1 キログラムだけ入れて価値 5 を得ます。最終的な価値は `18 + 5 = 23` です。
|
||
|
||
3. ナップサックが制限するのは総重量で、品物を分割できるため、単位重量当たりの価値を比較すべきです。
|
||
A は総価値が高くても、1 キログラム当たりの価値は B より低くなっています。A を先に入れてナップサックを満たすと、価値 20 しか得られません。
|
||
|
||
### 3. 2 つのポインタを次にどう動かすか
|
||
|
||
仕切り板の高さが `[1, 8, 6, 2, 5]` であるとき、先頭と末尾に置いた 2 つのポインタを使って最大容量を求めます。
|
||
容量は「2 枚の仕切り板のうち低いほうの高さ × 2 枚の仕切り板のインデックスの差」です。
|
||
|
||
<!-- numbered-subquestions -->
|
||
|
||
1. 最初は左のポインタがインデックス 0、右のポインタがインデックス 4 にあります。現在の容量はいくつですか?次にどちらのポインタを動かしますか?
|
||
2. 問い 1 で選んだポインタを 1 回動かした後、2 つのポインタはそれぞれどのインデックスにありますか?このときの容量はいくつですか?次はどちらのポインタを動かしますか?
|
||
3. 現在の 2 枚の仕切り板について、低い仕切り板のポインタを動かすことも、高い仕切り板のポインタを動かすこともできます。より大きな容量を得られる可能性が残るのはどちらですか?その理由も説明してください。
|
||
|
||
??? success "解答"
|
||
|
||
1. 現在の容量は `min(1, 5) × (4 - 0) = 4` です。左側の仕切り板のほうが低いため、左のポインタを動かします。
|
||
|
||
2. 左のポインタを動かすと、2 つのポインタはそれぞれインデックス 1 と 4 にあります。現在の容量は
|
||
`min(8, 5) × (4 - 1) = 15` です。右側の仕切り板のほうが低いため、次は右のポインタを動かします。
|
||
|
||
3. 低い仕切り板に対応するポインタを動かす場合に限り、より大きな容量を得られる可能性が残ります。高い仕切り板を動かすと、2 枚の間の距離は必ず短くなり、容器の高さは動かしていない低い仕切り板によって引き続き制限されるため、
|
||
高さは変わらないか低くなります。したがって、容量が移動前より大きくなることはありません。低い仕切り板を動かした場合にだけ、より高い仕切り板に出会える可能性があります。
|
||
|
||
## 15.6.2 プログラミング演習
|
||
|
||
### 1. 分数ナップサック
|
||
|
||
同じ長さの配列 `wgt` と `val` が与えられ、`wgt[i] > 0`、`val[i] >= 0`、ナップサックの容量は `cap >= 0` です。
|
||
各種類の品物は 1 個ずつしかありませんが、その一部だけを入れることもできます。
|
||
得られる価値は、入れた重さがその品物の総重量に占める割合に応じて決まります。貪欲法を使い、
|
||
ナップサックで得られる最大の総価値を実数で返してください。
|
||
|
||
??? tip "解法のヒント"
|
||
|
||
1. まず、各品物の単位重量当たりの価値 val[i] / wgt[i] を計算します。除算結果の小数部分も残します
|
||
2. 単位重量当たりの価値が高い品物からナップサックへ入れます
|
||
3. 残り容量が現在の品物の重さより小さければ、ナップサックをちょうど満たす分だけ入れて終了します
|