SlideShare a Scribd company logo
1 of 38
競技プログラミング講義
#3 「貪欲法」
貪欲法 (greedy algorithm)
●

●

「最適なもの」を常にとり続けることで数
値の最大化を達成するための方法
実装力<発想力
最適なもの
●

●

他のものに比べてどんな点においても優っ
ているようなもの
それを選んだことで、他のものを選んだ場
合より損することが全くないようなもの
例題
●

数の列 A[1],A[2],...,A[N] がある

●

K(1≦K≦N) 個とって和を最大にしたい

●

Sample
A = {1 , 4 , 9 , 2 , 3} , K = 3
例題
●

数の列 A[1],A[2],...,A[N] がある

●

K(1≦K≦N) 個とって和を最大にしたい

●

Sample
A = {1 , 4 , 9 , 2 , 3} , K = 3

●

Answer
16 ( 4 + 9 + 3 )
例題解説
●

●

●

現在の時点で選ばれていない数のうち一番
大きな数を考える
この数は他の数より勝っている
他の数(これより小さな数)をとることで
和がより大きくなることはない
さらに
●

●

●

「残っているものの中で一番大きなものを
とる」というのを順次繰り返していくと結
局大きなものから順にとっていくことにな
っている
これは大きい順にソートして、前から K 個
とるということ
9,4,3,2,1
さらに
●

●

●

「残っているものの中で一番大きなものを
とる」というのを順次繰り返していくと結
局大きなものから順にとっていくことにな
っている
これは大きい順にソートして、前から K 個
とるということ(ソートは簡単にできる)
9,4,3,2,1
さらに
●

●

●

「残っているものの中で一番大きなものを
とる」というのを順次繰り返していくと結
局大きなものから順にとっていくことにな
っている
これは大きい順にソートして、前から K 個
とるということ(ソートは簡単にできる)
9,4,3,2,1
さらに
●

●

●

「残っているものの中で一番大きなものを
とる」というのを順次繰り返していくと結
局大きなものから順にとっていくことにな
っている
これは大きい順にソートして、前から K 個
とるということ(ソートは簡単にできる)
9,4,3,2,1
一応厳密な感じで
●

選んだ数の列を B[1],B[2],...,B[K] とする

●

S = B[1] + B[2] + … + B[K]

●

このうち B[1] を変更(→ B'[1]) したとする

●

変更した後の数は選び方から元の数以下

●

よって変更後の和
S' = B[2] ~ B[K] の和 + B'[1]
≦ B[2] ~ B[K] の和 + B[1] = S
Greedy Point①
●

どのような貪欲をとればよいかがわかりに
くい時
→ 先ほどの証明のように
「どこをどう少し変えてみても悪くならな
い」ようなものを探せば良い
Greedy Point②
●

ソートすることによって貪欲法が行えるよ
うになる場合が多くある

●

とりあえずソートしてみるのも手

●

ソートの実装方法
Greedy Point②
●

ソートすることによって貪欲法が行えるよ
うになる場合が多くある

●

とりあえずソートしてみるのも手

●

ソートの実装方法
→ 自分で実装しなくてもちゃんとソートし
てくれる関数が用意されている
Greedy Point③
●

●

「全ての点において」というのが重要
ほとんどの点で優っていても一つでも負け
ていればそれは「全ての点において優れて
いる」ということにはならない
Greedy Point③ :例
●

A 君と B 君がいる

●

教科のテストの点数が
–
–

●

A 君は全て 100 点
B 君は全て 99 点

優っているのはどっち?
Greedy Point③ :例
●

A 君と B 君がいる

●

全ての教科のテストの点数が
–
–

●

A 君は全て 100 点
B 君は全て 99 点

優っているのはどっち?
→A君
Greedy Point③ :例
●

A 君と B 君がいる

●

数学以外の全ての教科のテストの点数が
–

A 君は 100 点

–

B 君は 0 点

●

数学は A 君が 99 点、 B 君が 100 点

●

優っているのはどっち?
→ 決められない
Greedy Point③ :例
●

A 君と B 君がいる

●

全ての教科のテストの点数が
–
–

●

A 君は全て 100 点
B 君は全て 99 点

優っているのはどっち?
Greedy Point③ :例題 1
●

●

●

N 個の扉があり、現在 P 個の鍵を持ってい
る
i 番目の扉は A[i] 個の鍵で開けることがで
き、 B[i] 個の鍵が新たに手に入る(使った
鍵は捨てられる)
同じ扉からは一度しか鍵は手に入らない
Greedy Point③ :例題 1
●

●

2つの状態 A,B があるとする
状態 A と状態 B ですでに開けた扉は全て
同じ

●

状態 A の方が持っている鍵の数は多い

●

優れているのはどっち?
Greedy Point③ :例題 1
●

●

2つの状態 A,B があるとする
状態 A と状態 B ですでに開けた扉は全て
同じ

●

状態 A の方が持っている鍵の数は多い

●

優れているのはどっち?
→A
Greedy Point③ :例題 1
●

●

●

N 個の扉があり、現在 P 個の赤い鍵と Q
個の青い鍵を持っている
i 番目の扉は A1[i] 個の赤い鍵と A2[i] 個の
青い鍵で開けることができ、 B1[i] 個の赤
い鍵と B2[i] の青い鍵が新たに手に入る
(使った鍵は捨てられる)
同じ扉からは一度しか鍵は手に入らない
Greedy Point③ :例題 1
●

●

2つの状態 A,B があるとする
状態 A と状態 B ですでに開けた扉は全て
同じ

●

状態 A の方が持っている鍵の合計数は多い

●

優れているのはどっち?

●

→ 決められない
Greedy Point③ まとめ
●

●

このように、状態の優劣が決められないよ
うな問題には貪欲法は適用できない
ただし、いくつかのパラメータを固定する
と適用できることもある
(例題 2 では赤い鍵の数を固定すると青い
鍵の数に対して貪欲法を使える)
〜実装タイム〜
AOJ0567 「最高のピザ」
ソートの方法
●

最初の方に
#include<algorithm>
using namespace std;
を追加

●

ソートしたい配列に対して
sort(a,a+N); //a は配列名、 N はサイズ
reverse(a,a+N);
ヒント
●

選ぶ個数によって値段が変わる
→ 何個選ぶかに注目
ヒント
●

選ぶ個数によって値段が変わる
→ 何個選ぶかに注目

●

選ぶ個数を固定する(決める)
→ 値段が決まる
→ 求めるのはカロリーが最大の時
解説
●

選ぶ個数によって値段が変わる
→ 選ぶ個数を固定する( k とする)
→ 値段が固定される
解説
●

選ぶ個数によって値段が変わる
→ 選ぶ個数を固定する( k とする)
→ 値段が固定される

●

求めるのはカロリーが最大
→ トッピングをカロリーの大きい順にソー
トして前から k 個選ぶ
これを全ての k に対して調べる
〜実装タイム〜
AOJ0112 「 A Milk Shop 」
ヒント
●

●

「待ち時間の合計」を違う見方で考えてみ
る
i 番目が t[i] 番目にくるとすると、 ( 待ち時
間を w[i] とする)
「待ち時間の合計」
=
ヒント
●

●

「待ち時間の合計」を違う見方で考えてみ
る
i 番目が t[i] 番目にくるとすると、 ( 待ち時
間を w[i] とする)
「待ち時間の合計」
= w[1]*(N – t[1]) + w[2]*(N-t[2]) + …
これを最小化する
ヒント
●

直感的には…?
解説
●

先ほどのように表すと、
大きい w[i] には小さい N - t[i] を割り当てた
い
→ 待ち時間が長い人は後の方に並べたい
解説
●

先ほどのように表すと、
大きい w[i] には小さい N - t[i] を割り当てた
い
→ 待ち時間が長い人は後の方に並べたい

●

小さい順にソートという並べ方が答え

●

なぜ?
解説
●

先ほどのように表すと、
大きい w[i] には小さい N - t[i] を割り当てた
い
→ 待ち時間が長い人は後の方に並べたい

●

小さい順にソートという並べ方が答え

●

なぜ?
→ どう入れ替えても悪くなる

More Related Content

More from Ryunosuke Iwai

More from Ryunosuke Iwai (6)

Rth number
Rth numberRth number
Rth number
 
Ice
IceIce
Ice
 
Water flow
Water flowWater flow
Water flow
 
文字列処理
文字列処理文字列処理
文字列処理
 
データ処理
データ処理データ処理
データ処理
 
Arduino
ArduinoArduino
Arduino
 

貪欲