37
プログラミングコンテストでの 乱択アルゴリズム 東京大学情報理工学系研究科 秋葉 拓哉 / [[iwi]] 1 2012/06/12 ディー・エヌ・エー 渋谷オフィス (TopCoder Meetup in Japan)

プログラミングコンテストでの乱択アルゴリズム

Embed Size (px)

Citation preview

Page 1: プログラミングコンテストでの乱択アルゴリズム

プログラミングコンテストでの

乱択アルゴリズム

東京大学情報理工学系研究科

秋葉 拓哉 / [[iwi]]

1

2012/06/12 ディー・エヌ・エー 渋谷オフィス (TopCoder Meetup in Japan)

Page 2: プログラミングコンテストでの乱択アルゴリズム

自己紹介

• 秋葉 拓哉 / [[iwi]]

– Twitter: @iwiwi

• 東京大学 情報理工学系研究科 コンピュータ科学専攻

• プログラミングコンテスト凄い好き

– 世界大会の常連をやっています

– ここ 1 年で 3 回,来月も行きます

• プログラミングコンテストチャレンジブック共著

2

Page 3: プログラミングコンテストでの乱択アルゴリズム

今日の話

「乱択アルゴリズム」

• 既存の乱択アルゴリズムの紹介を延々とはしません

– そういうアルゴリズム解説は一杯あります

• コンテストに焦点を絞り,乱択アルゴリズムを設計

できるようにする,ということを目指す

(簡単めの話になります,中上級者の方々ごめんなさい)

3

Page 4: プログラミングコンテストでの乱択アルゴリズム

最近のコンテストでの状況

• 京都大学プログラミングコンテスト 2011

– 問題D : 列の構成

– 問題G : XOR 回路

• Google Code Jam 2012

– R1C C : Equal Sums

– R2 B : Aerobics

• その他 (2012)

– ICPC OB/OG 会 冬コンテスト : Sunny Graph

– ARC #3 D : シャッフル席替え

出題が激増中! 4

Page 5: プログラミングコンテストでの乱択アルゴリズム

乱択アルゴリズムとは?

5

Page 6: プログラミングコンテストでの乱択アルゴリズム

乱択アルゴリズムとは?

乱数を用いて挙動を決めるアルゴリズム

乱数を用いるので,

• 計算時間が一定ではないかもしれない

– そういうものを,Las Vegas アルゴリズムと呼ぶ

• さらに,計算結果が必ず正しいとは限らないものも

– そういうものを,Monte Carlo アルゴリズムと呼ぶ

6

Page 7: プログラミングコンテストでの乱択アルゴリズム

乱択アルゴリズムの重要な原理

定番教科書 Randomized Algorithms の序文より

(Rajeev Motwani & Prabhakar Raghavan)

• Foiling an adversary

• Random sampling

• Abundance of witnesses

• Fingerprinting and hashing

• Random re-ordering

• Load balancing

• Rapidly mixing Markov chains

• Isolation and symmetry breaking

• Probabilistic methods and existence proofs

7

Page 8: プログラミングコンテストでの乱択アルゴリズム

コンテストでは?

定番教科書 Randomized Algorithms の序文より

(Rajeev Motwani & Prabhakar Raghavan)

• Foiling an adversary

• Random sampling

• Abundance of witnesses

• Fingerprinting and hashing

• Random re-ordering

• Load balancing

• Rapidly mixing Markov chains

• Isolation and symmetry breaking

• Probabilistic methods and existence proofs

8

→ ケース 1, 2 両方

→ ケース 2 後半

→ 文字列アルゴリズム等

→ 二分探索の枝刈り,嘘解法

Page 9: プログラミングコンテストでの乱択アルゴリズム

ケース 1 : 多数あるものを 1 つ見つける

9

Page 10: プログラミングコンテストでの乱択アルゴリズム

最近のコンテストでの状況

• 京都大学プログラミングコンテスト 2011

– 問題D : 列の構成

– 問題G : XOR 回路

• Google Code Jam 2012

– R1C-C : Equal Sums

– R2-B : Aerobics

• AtCoder (2012)

– ARC#3-D : シャッフル席替え

10

この 4 問はいずれも,

多数あるものを1つ見つける

ために乱択を用いる

Page 11: プログラミングコンテストでの乱択アルゴリズム

基本原理

11

𝑁 個の箱があります.

開けるまで分かりませんが,

半分はアタリだと知っています.

箱を開けて,アタリを見つけよう!

𝑁 個

Page 12: プログラミングコンテストでの乱択アルゴリズム

基本原理

12

𝑁 個

【乱択アルゴリズム】

アタリが出るまで,ランダムに選んで開ける

【開ける箱の個数の期待値】

期待値 ≤ 1 +1

2+1

4+1

8+⋯ ≤ 2 個

アタリが大量にあるので,すぐにあたる

Random sampling

Page 13: プログラミングコンテストでの乱択アルゴリズム

ランダムである意味

13

(´・_・`)

大量にあるなら,とにかく選べばアタリが出てくる.

なんでもいいけど,まあランダムでいっか.

Page 14: プログラミングコンテストでの乱択アルゴリズム

ランダムである意味

14

(´・_・`)

大量にあるなら,とにかく選べばアタリが出てくる.

なんでもいいけど,まあランダムでいっか.

( ・`д・´)

違うぞ,ランダムじゃなければいけない

舐めてんのか!!!!!

Page 15: プログラミングコンテストでの乱択アルゴリズム

ランダムである意味

いっぱいあってどうせすぐあたるから,

選び方はどうでも良い?前から順とかはどうか?

15

こういう時は全然平気だが

「意地悪」をされるとひとたまりもない

Page 16: プログラミングコンテストでの乱択アルゴリズム

ランダムである意味

• 前からに限らず,取る順番が決まっているので

あれば,必ず「意地悪」がされ得る

– 最初に取る 𝑁/2 個をハズレにしといてやればよい

• 一方,ランダムの場合,意地悪が出来ない

– どれを取るかわからない

– 何されても 2 回程度で当たる

16

Foiling an adversary

Page 17: プログラミングコンテストでの乱択アルゴリズム

ランダムである意味

• 実際には,相手が居て,意地悪され得るような

場合とは限らない

• しかし,分布の偏りはよくある

– 例えば,ハズレは近いところに連続する傾向とか

– そういうので頭からやってしまうと,やはりまずい

• 従って,ランダムに選ぶことに意味がある

17

Page 18: プログラミングコンテストでの乱択アルゴリズム

問題「列の構成」(KUPC’11 D) http://old.atcoder.jp/problem/detail/78

長さ 𝑁 の 0,1 からなる列 𝑆 をつくれ,ただし

• 列 𝑐𝑖 = {𝑐𝑖,1, 𝑐𝑖,2, … , 𝑐𝑖,𝑁2

} が与えられている

•𝑁

8≤ 𝑆𝑐𝑖,𝑗𝑗 ≤

3𝑁

8 を満たさなければならない

18

• 長さ 𝑁

2 の部分列たちの和を

𝑁

8 から

3𝑁

8 に入れたい

• 𝑆 をランダム列とすると,和の期待値は 𝑁

4 (←OK)

• ランダム列はそこそこの確率で条件を満たしそう

• 生成してみてチェックして OK なら出力

(確率についての考察はアルゴリズムの単純さに比べ複雑

http://www.kupc.jp/2011/editorial/D.pdf)

Page 19: プログラミングコンテストでの乱択アルゴリズム

問題「Aerobics」(GCJ’12 R2 B) http://code.google.com/codejam/contest/1842485/dashboard#s=p1

• 問題文の条件より,大きい方から置いていくと,そ

こまでどのような置き方をしていても,次の●の中

心が置ける場所が,全体の 1

5 はある

• よって,ランダムな場所を選んで,

• 置けるかチェックし,置けるなら置く

19

(詳細省略)

• □の上に●を置いていく

• □は十分大きいことが保証されている

Page 20: プログラミングコンテストでの乱択アルゴリズム

ケース 2 : 推定する

20

Page 21: プログラミングコンテストでの乱択アルゴリズム

モンテカルロ法

• 確率 𝑝 を求めたい

• でも,標本空間の全体ついて調べるのは無理

– 大きすぎたり,連続だったり

21

Random sampling

このような場合に,標本空間をランダムに選んで

調べ,それから確率を推定する

(何故ランダム? → 前同様,偏ってても大丈夫に)

Foiling an adversary

Page 22: プログラミングコンテストでの乱択アルゴリズム

円周率

22

• [0, 1] × [0, 1] の上でランダムな点

• 原点からの距離が 1 以下かを調べる

• 青の面積が推定できて,円周率が推定できる!

(円周率計算にはもっと良い方法があるのでこれは使われない)

Page 23: プログラミングコンテストでの乱択アルゴリズム

問題「シャッフル席替え」(ARC#3-D) http://arc003.contest.atcoder.jp/tasks/arc003_4

• 実際にランダムに何度もやってみる

23

• 円形に人が順に 1,2,… , 𝑛 と並んでる

• 二人を選び場所を入れ替える,をランダムに 𝑘 回

• 𝑚 組の指定された二人組が全く隣り合わない確率は?

𝑛,𝑚, 𝑘 10 程度,許容誤差 2 × 10−3

Page 24: プログラミングコンテストでの乱択アルゴリズム

モンテカルロ法の収束速度

• 正しい確率を 𝑝 とする

• 𝑛 回の試行での推定値 𝑝𝑛 は,二項分布 𝐵𝑖 𝑛, 𝑝/𝑛

– 分散 𝑝(1 − 𝑝)/𝑛

• よって,絶対誤差はだいたい 1

𝑛 に比例

– 精度を 10 倍にするには,𝑛 は 100 倍

24

Page 25: プログラミングコンテストでの乱択アルゴリズム

問題「PM3」(POJ 3213) http://poj.org/problem?id=3213

• 𝐴 × 𝐵 を素直に計算すると 𝑂 𝑛3 ,間に合わない

(もっと計算量の良い掛け算アルゴリズムもあるが,無理)

• 判定だけ出来れば良い点を生かせないか

25

• 𝑛 × 𝑛 行列 𝐴, 𝐵, 𝐶 が与えられます

• 𝐴 × 𝐵 = 𝐶 であるか答えてください

𝑛 ≤ 1000

Page 26: プログラミングコンテストでの乱択アルゴリズム

問題「PM3」(POJ 3213) http://poj.org/problem?id=3213

【解法】

• ランダムなベクトル 𝑥 を作る

• 𝐴𝐵𝑥 = 𝐶𝑥 であるかで推定する

– 𝐴𝐵𝑥 は 𝐴 𝐵𝑥 の順で計算すれば 𝑂 𝑛2 !

• 直感的にも,行列が違ったら違うベクトルが出てきそう

• 真面目に考えると:行列が違うのに等しくなったとすると

– 𝐴𝐵と 𝐶に異なる行が 1 つは存在,その差を 𝑣 とおくと 𝑣𝑥 = 0.

– すなわち,𝑥𝑛 = − 𝑣𝑖𝑥𝑖𝑛−1𝑖=1 /𝑣𝑛 となっている.

– 𝑥𝑛を𝐾個の数からランダムに選んでるとすると,確率高々1/𝐾

26

Random sampling

Abundance of witnesses

Page 27: プログラミングコンテストでの乱択アルゴリズム

問題「PM3」(POJ 3213) http://poj.org/problem?id=3213

• 𝐴𝐵𝑥 ≠ 𝐶𝑥 となるような 𝑥 が有れば,

𝐴𝐵 ≠ 𝐶 とわかる

• こういう 𝑥 を witness (証人) と呼ぶ

• witness が一杯ある状況では,ランダムを用いて

witness を 1 つ手に入れてしまえば良い

– 逆に全然見つからなかったら 𝐴𝐵 = 𝐶 と判断

27

Random sampling Abundance of witnesses

Page 28: プログラミングコンテストでの乱択アルゴリズム

その他での乱択の登場

28

Page 29: プログラミングコンテストでの乱択アルゴリズム

その他の乱択の登場

既成アルゴリズム・データ構造・テクニックの利用

• Rolling-Hash を用いた文字列検索 (Rabin-Karp) (→ プログラミングコンテストチャレンジブック 第二版のみ P.332)

• Tutte 行列を用いた一般グラフの最大マッチング (→ プログラミングコンテストチャレンジブック P.197)

• Treap, RBST (→ プログラミングコンテストでのデータ構造2 http://slidesha.re/GW3BH6)

• Miller-Rabin 素数判定

• 二分探索の枝刈り

嘘解法

• 山登り法

• ランダム回転

29

Page 30: プログラミングコンテストでの乱択アルゴリズム

二分探索の枝刈り

• 各 𝑖, 𝑥 に対し,check(i, x) は true か false を返す

• どれかの 𝑖 で true が得られる最小の 𝑥 を計算したい

→ x の値で二分探索 (常套手段)

30

false

𝑥

true

false true

false true

ここの 𝒙 の値を知りたい!

check(1, 𝑥)

check(2, 𝑥)

check(3, 𝑥)

0

Page 31: プログラミングコンテストでの乱択アルゴリズム

二分探索の枝刈り

• check(i, x) は各 i に対して,x の増加に伴いどこかで false から true

になる単調な関数

• どれかの i に対し check(i, x) が true になる最小の x を求めている

• このコードでは,check が 𝑇𝑁 回 呼ばれる

31

double lb = 0, ub = 1E10;

for (int iter = 0; iter < T; ++iter) {

double mid = (lb + ub) / 2;

bool f = false;

for (int i = 0; i < N; ++i) f |= check(i, mid);

if (f) ub = mid;

else lb = mid;

}

𝑇 回イテレーションする

二分探索

𝑛 個 check 呼んで

or をとる

どれか true になってたら

下へ,そうでなければ上へ

Page 32: プログラミングコンテストでの乱択アルゴリズム

二分探索の枝刈り

• i のループを外に出した

• これだけだと何も変わらない

32

double ans = 1E10;

for (int i = 0; i < N; ++i) {

double lb = 0, ub = 1E10;

for (int iter = 0; iter < T; ++iter) {

double mid = (lb + ub) / 2;

if (check(i, mid)) ub = mid;

else lb = mid;

}

ans = min(ans, ub);

}

𝑖 のループ

二分探索

𝑛 個の値の最小値を求める

Page 33: プログラミングコンテストでの乱択アルゴリズム

二分探索の枝刈り

• 現在の暫定答え ans より大きい答えには興味が無い

• 従って,そこで check を一度計算すると,二分探索しなくてよい!

33

double ans = 1E10;

for (int i = 0; i < N; ++i) {

if (check(i, ans) == false) continue;

double lb = 0, ub = 1E10;

for (int iter = 0; iter < T; ++iter) {

double mid = (lb + ub) / 2;

if (check(i, mid)) ub = mid;

else lb = mid;

}

ans = min(ans, ub);

}

←枝刈り!

Page 34: プログラミングコンテストでの乱択アルゴリズム

二分探索の枝刈り

• さらに 𝑖 をランダム順にループすることにすると,

check を呼ぶ回数の期待値を見積もれる

1. 最初は必ず二分探索する

2. 次は 1/2 の確率で二分探索する

3. その次は 1/3 の確率で二分探索する

𝑁 + 𝑇 +𝑇

2+𝑇

3+⋯≒𝑁 + 𝑇 log𝑁 回

→ 𝑇𝑁 回から随分と減らすことに成功!

34

Page 35: プログラミングコンテストでの乱択アルゴリズム

まとめ

話したこと

• 乱択アルゴリズムとは何か

• 多数あるものを 1 つ見つける

• 性質を推定する

• その他:二分探索の枝刈り

35

Page 36: プログラミングコンテストでの乱択アルゴリズム

出題側の課題

• 乱択アルゴリズムの出題は上手くいっているか?

• 乱択アルゴリズムの成功確率を保証しようとすると,ど

うしても,「ゆるい」問題になる

• 変なヒューリスティクスなどが通ってしまいやすい

– 想定できれば落とせるかもだが,全てを想定するのは無理

– 想定できたものだけが落ちる? → 枝刈り探索系と類似の問題点

36

Page 37: プログラミングコンテストでの乱択アルゴリズム

𠮷田悠一さん

(@oxy)

謝辞

有用なコメントを頂きました,感謝

37

岩田陽一さん

(wata / @wata_orz)