More Related Content
Similar to プログラミングコンテストでの乱択アルゴリズム
Similar to プログラミングコンテストでの乱択アルゴリズム (20)
More from Takuya Akiba (10)
プログラミングコンテストでの乱択アルゴリズム
- 2. 自己紹介
• 秋葉 拓哉 / [[iwi]]
– Twitter: @iwiwi
• 東京大学 情報理工学系研究科 コンピュータ科学専攻
• プログラミングコンテスト凄い好き
– 世界大会の常連をやっています
– ここ 1 年で 3 回,来月も行きます
• プログラミングコンテストチャレンジブック共著
2
- 3. 今日の話
「乱択アルゴリズム」
• 既存の乱択アルゴリズムの紹介を延々とはしません
– そういうアルゴリズム解説は一杯あります
• コンテストに焦点を絞り,乱択アルゴリズムを設計
できるようにする,ということを目指す
(簡単めの話になります,中上級者の方々ごめんなさい)
3
- 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
- 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
- 8. コンテストでは?
定番教科書 Randomized Algorithms の序文より
(Rajeev Motwani & Prabhakar Raghavan)
• Foiling an adversary
→ ケース 1, 2 両方
• Random sampling
• Abundance of witnesses → ケース 2 後半
• Fingerprinting and hashing → 文字列アルゴリズム等
• Random re-ordering → 二分探索の枝刈り,嘘解法
• Load balancing
• Rapidly mixing Markov chains
• Isolation and symmetry breaking
• Probabilistic methods and existence proofs
8
- 10. 最近のコンテストでの状況
• 京都大学プログラミングコンテスト 2011
– 問題D : 列の構成
– 問題G : XOR 回路 この 4 問はいずれも,
• Google Code Jam 2012 多数あるものを1つ見つける
– R1C-C : Equal Sums ために乱択を用いる
– R2-B : Aerobics
• AtCoder (2012)
– ARC#3-D : シャッフル席替え
10
- 11. 基本原理
𝑁個
𝑁 個の箱があります.
開けるまで分かりませんが,
半分はアタリだと知っています.
箱を開けて,アタリを見つけよう!
11
- 12. 基本原理
𝑁個
【乱択アルゴリズム】 Random sampling
アタリが出るまで,ランダムに選んで開ける
【開ける箱の個数の期待値】
1 1 1
期待値 ≤ 1 + + + +⋯≤2個
2 4 8
アタリが大量にあるので,すぐにあたる
12
- 18. 問題「列の構成」(KUPC’11 D)
http://old.atcoder.jp/problem/detail/78
長さ 𝑁 の 0,1 からなる列 𝑆 をつくれ,ただし
• 列 𝑐 𝑖 = {𝑐 𝑖,1 , 𝑐 𝑖,2 , … , 𝑐 𝑖, 𝑁 } が与えられている
2
𝑁 3𝑁
• ≤ 𝑗 𝑆 𝑐 𝑖,𝑗 ≤ を満たさなければならない
8 8
𝑁 𝑁 3𝑁
• 長さ の部分列たちの和を から に入れたい
2 8 8
𝑁
• 𝑆 をランダム列とすると,和の期待値は (←OK)
4
• ランダム列はそこそこの確率で条件を満たしそう
• 生成してみてチェックして OK なら出力
(確率についての考察はアルゴリズムの単純さに比べ複雑
http://www.kupc.jp/2011/editorial/D.pdf)
18
- 19. 問題「Aerobics」(GCJ’12 R2 B)
http://code.google.com/codejam/contest/1842485/dashboard#s=p1
(詳細省略)
• □の上に●を置いていく
• □は十分大きいことが保証されている
• 問題文の条件より,大きい方から置いていくと,そ
こまでどのような置き方をしていても,次の●の中
1
心が置ける場所が,全体の はある
5
• よって,ランダムな場所を選んで,
• 置けるかチェックし,置けるなら置く
19
- 21. モンテカルロ法
• 確率 𝑝 を求めたい
• でも,標本空間の全体ついて調べるのは無理
– 大きすぎたり,連続だったり
このような場合に,標本空間をランダムに選んで
調べ,それから確率を推定する Random sampling
(何故ランダム? → 前同様,偏ってても大丈夫に)
Foiling an adversary
21
- 22. 円周率
• [0, 1] × [0, 1] の上でランダムな点
• 原点からの距離が 1 以下かを調べる
• 青の面積が推定できて,円周率が推定できる!
(円周率計算にはもっと良い方法があるのでこれは使われない)
22
- 23. 問題「シャッフル席替え」(ARC#3-D)
http://arc003.contest.atcoder.jp/tasks/arc003_4
• 円形に人が順に 1,2, … , 𝑛 と並んでる
• 二人を選び場所を入れ替える,をランダムに 𝑘 回
• 𝑚 組の指定された二人組が全く隣り合わない確率は?
𝑛, 𝑚, 𝑘 10 程度,許容誤差 2 × 10−3
• 実際にランダムに何度もやってみる
23
- 24. モンテカルロ法の収束速度
• 正しい確率を 𝑝 とする
• 𝑛 回の試行での推定値 𝑝 𝑛 は,二項分布 𝐵𝑖 𝑛, 𝑝/𝑛
– 分散 𝑝(1 − 𝑝)/𝑛
1
• よって,絶対誤差はだいたい に比例
𝑛
– 精度を 10 倍にするには,𝑛 は 100 倍
24
- 25. 問題「PM 3」(POJ 3213)
http://poj.org/problem?id=3213
• 𝑛 × 𝑛 行列 𝐴, 𝐵, 𝐶 が与えられます
• 𝐴 × 𝐵 = 𝐶 であるか答えてください
𝑛 ≤ 1000
• 𝐴 × 𝐵 を素直に計算すると 𝑂 𝑛3 ,間に合わない
(もっと計算量の良い掛け算アルゴリズムもあるが,無理)
• 判定だけ出来れば良い点を生かせないか
25
- 26. 問題「PM 3」(POJ 3213)
http://poj.org/problem?id=3213
Abundance of witnesses
【解法】
Random sampling
• ランダムなベクトル 𝑥 を作る
• 𝐴𝐵𝑥 = 𝐶𝑥 であるかで推定する
– 𝐴𝐵𝑥 は 𝐴 𝐵𝑥 の順で計算すれば 𝑂 𝑛2 !
• 直感的にも,行列が違ったら違うベクトルが出てきそう
• 真面目に考えると:行列が違うのに等しくなったとすると
– 𝐴𝐵と 𝐶に異なる行が 1 つは存在,その差を 𝑣 とおくと 𝑣𝑥 = 0.
𝑛−1
– すなわち,𝑥 𝑛 = − 𝑖=1 𝑣 𝑖 𝑥 𝑖 /𝑣 𝑛 となっている.
– 𝑥 𝑛 を𝐾個の数からランダムに選んでるとすると,確率高々1/𝐾
26
- 27. 問題「PM 3」(POJ 3213)
http://poj.org/problem?id=3213
• 𝐴𝐵𝑥 ≠ 𝐶𝑥 となるような 𝑥 が有れば,
𝐴𝐵 ≠ 𝐶 とわかる
• こういう 𝑥 を witness (証人) と呼ぶ
• witness が一杯ある状況では,ランダムを用いて
witness を 1 つ手に入れてしまえば良い
– 逆に全然見つからなかったら 𝐴𝐵 = 𝐶 と判断
Abundance of witnesses Random sampling
27
- 29. その他の乱択の登場
既成アルゴリズム・データ構造・テクニックの利用
• Rolling-Hash を用いた文字列検索 (Rabin-Karp)
(→ プログラミングコンテストチャレンジブック 第二版のみ P.332)
• Tutte 行列を用いた一般グラフの最大マッチング
(→ プログラミングコンテストチャレンジブック P.197)
• Treap, RBST
(→ プログラミングコンテストでのデータ構造2 http://slidesha.re/GW3BH6)
• Miller-Rabin 素数判定
• 二分探索の枝刈り
嘘解法
• 山登り法
• ランダム回転
29
- 30. 二分探索の枝刈り
0
𝑥
check(1, 𝑥) false true
check(2, 𝑥) false true
check(3, 𝑥) false true
ここの 𝒙 の値を知りたい!
• 各 𝑖, 𝑥 に対し,check(i, x) は true か false を返す
• どれかの 𝑖 で true が得られる最小の 𝑥 を計算したい
→ x の値で二分探索 (常套手段)
30
- 31. 二分探索の枝刈り
double lb = 0, ub = 1E10;
for (int iter = 0; iter < T; ++iter) { 𝑇 回イテレーションする
double mid = (lb + ub) / 2; 二分探索
bool f = false; 𝑛 個 check 呼んで
for (int i = 0; i < N; ++i) f |= check(i, mid); or をとる
if (f) ub = mid; どれか true になってたら
else lb = mid; 下へ,そうでなければ上へ
}
• check(i, x) は各 i に対して,x の増加に伴いどこかで false から true
になる単調な関数
• どれかの i に対し check(i, x) が true になる最小の x を求めている
• このコードでは,check が 𝑇𝑁 回 呼ばれる
31
- 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); 𝑛 個の値の最小値を求める
}
• i のループを外に出した
• これだけだと何も変わらない
32
- 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);
}
• 現在の暫定答え ans より大きい答えには興味が無い
• 従って,そこで check を一度計算すると,二分探索しなくてよい!
33
- 34. 二分探索の枝刈り
• さらに 𝑖 をランダム順にループすることにすると,
check を呼ぶ回数の期待値を見積もれる
1. 最初は必ず二分探索する
2. 次は 1/2 の確率で二分探索する
3. その次は 1/3 の確率で二分探索する
𝑇 𝑇
𝑁 + 𝑇 + + + ⋯≒𝑁 + 𝑇 log 𝑁 回
2 3
→ 𝑇𝑁 回から随分と減らすことに成功!
34