Transcript Document

コンピュータアルゴリズム2
4. 分割統治法
田浦
http://www.logos.ic.i.u-tokyo.ac.jp
/~tau/lecture/software/
内容



分割統治法(divide-and-conquer)の考え方
 再帰呼び出しを有効利用したアルゴリズムの簡潔な記述
適用例
 クイックソート,マージソート,FFT, 行列積,etc
 その他の再帰呼び出し利用例
再帰呼び出しを含むプログラムの計算量
 漸化式
 分割統治の計算量の一般論
分割統治法のテンプレート

solve(X) {
if (trivial(X)) {
trivial_solve(X);
} else {
X1, X2, ..., Xp = divide(X);
A1 = solve(X1);
A2 = solve(X2);
...
Ap = solve(Xp);
return combine(A1, A2, ..., Ap);
}
}
X
X1
X2
X3
X4
分割統治法のマスター  再帰呼び出しの有効利用法のマスター
再帰呼び出しのマスターが重要な
理由


プログラムの「記述法」として
 さもなければ非常にややこしくなるプログラムの記述が非
常に簡潔になる
解法の「発想法」として
 「あたかも,より小さな問題の解はわかっている」と仮定し
て,解答を書けばいい
 数学での類似物:漸化式による解法
 最初から closed form での解を求めるのが難しい問題
を,いったん漸化式を書いてそれを解く,という方法
(用語の注)
再帰呼び出し=分割統治?

NO: ニュアンスとしては,「分割統治法」は,再帰呼び出しを
する際に問題のサイズが当初の問題より十分(定数倍)小さく
なっている場合をいうようである
 たとえば普通以下を「分割統治」とは呼ばない
 int fib(n) { if (n < 2) return 1; else fib(n – 1) + fib(n – 2); }

しかしそうであろうとなかろうと,「再帰呼び出し」が「記述法・
発想法として有効」なことには違いない
再帰呼び出しの練習(1)

例題: n (整数)が与えられた際に,可能なすべての n 個の{0,
1}列(2n個ある)を列挙せよ
 0000...00
 0000...01
 0000...10
 ...
 1111...11
再帰呼び出しの練習(2)

n要素の整数の配列(a[0], ..., a[n–1])と目標値Tが与えられる.
n個から値を選び出してその和がTとなるようにできるか?
 例: a = { 2, 4, 3, 9 }, T = 5 解: 2 + 3 = 5
 例: a = { 2, 4, 3, 9 }, T = 8 解: なし
再帰呼び出しの練習(3)

例題: n 円盤のハノイの塔を解く(手順を表示する)プログラ
ムを書け
move 1 a  b
move 2 a  c
move 1 b  c
move 3 a  b
move 1 c  a
move 2 c  b
move 1 a  b
1
2
3
a
b
c
再帰呼び出しの練習(4)

1...nまでのすべての並び替えを列挙せよ
 123
 132
 213
 231
 312
 321

注:これらはどれも n に対して指数関数の計算時間を要する
アルゴリズムで,通常「分割統治法」とは呼ばない
「分割統治法」の例(1)
行列積
A00
A01
A
A10
A11

B00
B01
B
B10
C00
C
=
B11
A00  B00 +
A01  B10 =
C00
A00  B01 +
A01  B11 =
C01
A10  B00 +
A11  B10 =
C10
A10  B01 +
A11  B11 =
C11
C01
C10
C11
1辺 N の問題
 1辺N / 2の問題  8
「分割統治法」の例(2)
FFT (高速フーリエ変換)

フーリエ変換(連続関数)
g ( y) 

1
2



f ( x )e
 ixy
dx
離散フーリエ変換(サンプル数N)
  は1のN乗根の逆数 = e– i (2  / N)
N 1
g[k ] 

f [ j ]
jk
N
(k = 0, 1, ..., N – 1)
j0
FFTはこの計算を高速に行う方法
離散フーリエ変換の行列表示
N 1
gk 

f j
jk
N
j0
 g 0  1

 
 g1  1
 g   1
 2  
   

 
 g N 1   1
1
1

1

2


N 1


2


4



( N 1 ) 2




N 1


2 ( N 1 )






( N  1 )( N  1 )  


1
f0 

f1 

f2

 

f N 1 


通常の方法では明らかに N2 回の掛け算が必要
どのように「分割統治」(小さな問題へ分割)できるか
 簡単のため N は偶数(後でわかるように2のべき)とする
N = 8の場合の行列
1

1
1

1

1

1

1

1

1
1

1
1

2

2
=

3
=–

4

6
=

3

6

9

4

8

12

5

10

15 =

6

12

18

7

14

21
1
1

5

6
8

10

12
= –  12

15

18

16

20

24
–
20

25

30

24

30

36
= –
28

35

42
=
=

4

1
1 

7
 
14 


21
 
28 


35
 
42 
 
49 
 
偶数行(0, 2, 4, 6)の計算方法
+
しかもこの計算が良く見るとN/2 点 FFTそのもの
奇数行(1, 3, 5, 7)の計算方法
–
残念ながらここはFFTそのものではなく一工夫必要
奇数行の工夫
1

1

1

1


1

2

3

6

5

10

7

14
3
  f 0 
1
  
9
  f1   1

15  

f2
1

  
 
21 
   f 3   1
1
1

2

4

4

8

6

12
N / 2点FFT
1  f 0 


6
   f1 
2
12  
 f2 



3
18  
    f 3 
N 1
g 2k 

f j
2 jk
N
f j
jk
N /2
導出(偶数行)
j0
N 1


j0
N / 2 1



N 1
f j
jk
N /2


f j
j0
j N / 2
N / 2 1
N / 2 1

f j
j0
jk
N /2


f j  N / 2
j0
N / 2 1

(f
j0
j
jk
N /2
 f j  N / 2 )
jk
N /2
jk
N /2
N 1
g 2 k 1 

f j
2 jk  j
N
f j
jk
N /2
導出(奇数行)
j0
N 1



j
N
j0
N / 2 1



N 1
f j
jk
N /2

j
N


f j
j0
j N / 2
N / 2 1
N / 2 1

f j
j0
jk
N /2

j
N


N / 2 1

(f
j0
j

f j  N / 2
j0
 f j  N / 2 ) 
j
N
jk
N /2
jk
N /2
j
N
jk
N /2
(  )
j
N
FFTの計算量は?


O(N log N)
ただし分割統治が続けられるよう, N が2のべきである必要が
ある
分割統治法の計算量に関する一般
論
問題設定(1)


以下のような分割統治法を考える
solve (X) {
if (size(X) = 1) return trivial_solve(X);
else {
X1, X2, ..., Xp = divide(X);
A1 = solve(X1);
...
Ap = solve(Xp);
return merge(A1, ..., Ap);
}
}
問題設定(2)

以下を仮定する.Xiの大きさを inとするとき,
 分割と解の併合(divideとmerge)にかかる計算量はあわせ
てO(nk)
 定数 c < 1 が存在し,各 i  c
 定数 d が存在し, 1k + 2k + ... + pk  d
 大きさ 1のデータに対する(trivial_solve(X)の)計算量は
高々定数(1とする)
定理

このとき大きさnのデータに対するこのアルゴリズムの計算量
T(n)は
 O (n )

k
T ( n )   O ( n log n )
 O ( n k  log 1 / c d )

k
d  1 のとき
d  1 のとき
d  1 のとき
いくつかの例


マージソート
 n が n/2 二つに分かれる
 分割・併合は O(n)
  k = 1, c = 1/2, d = 1  O(n log n)
クイックソート
 ただし,定理中の定数 c < 1 の存在を仮定する(実際には
成り立たない)
 分割・併合は O(n)
  k = 1, d = 1  O(n log n)
行列積



n が n/2 八つに分かれる
分割・併合は O(n2)
k = 2, c = 1/2, d = (1/2)2  8 = 2  O(n2 + log2) = O(n3)
アルゴリズム体操
チャレンジ問題:授業期間を通じて「できた」という人の報告を待つ
アルゴリズム体操(1)

2  2 行列の積は通常 8つの掛け算が必要である
a00
a10


a01
a11

b00
b01
c00
c01
c10
c11
=
b10
b11
[難] これを7つの掛け算(その代わり足し算引き算の数は増え
る)で行う方法がある.それを考えよ
それが見つかるとn  nの行列の掛け算をO(n2.81)で行う方法
が導かれる(nは2の冪としてよい)
アルゴリズム体操(2)

n個の要素からなる配列がある.これらの中でn/2個より多く
現れている要素があればそれを見つけ,そのような要素が
なければないと答えるアルゴリズムを作りたい
 [易] 計算量 O(n log n)のアルゴリズムを考えよ
 [難] 計算量 O(n)のアルゴリズムを考えよ
 hint: 分割統治法でk = 1, d < 1となるようなものを見出
せ
アルゴリズム体操(3)



時間計算量O(n log n)が保証されたクイックソートアルゴリズ
ムは,以下の意味で「安全な」pivot pをO(n)で見つけることが
できれば実現可能である(※)
 ある定数c < 1 が存在し
 a[i]  pであるiの個数  c n
 a[i]  pであるiの個数  c n
[易] (※) を証明せよ
[難] そのようなアルゴリズムFを見つけよ
 hint: 分割統治法でk = 1, d < 1であるようなものを見出せ
アルゴリズム体操(4)

n個の相異なる数からなる配列がある.中央値(nの偶奇に応
じn/2番目または (n+1)/2番目の値)を見つけたい
 [易] O(n log n)のアルゴリズムを見つけよ
 [難] O(n)のアルゴリズムを見つけよ
 hint : 前問で求めたアルゴリズムFを用いる.そして,こ
れを利用して分割統治法を使う(k = 1, d < 1)