introduction to algorithms - 情報知識ネット …k-sekine/slides/convexhull.pdfcontents 33.3...

201
INTRODUCTION TO ALGORITHMS 33. Computational Geometry 33.3 Finding the convex hull 33.4 Finding the closest pair of points 2011.5.26 関根 渓 (情報知識ネットワーク研究室 B4

Upload: buiquynh

Post on 17-Jul-2018

216 views

Category:

Documents


0 download

TRANSCRIPT

INTRODUCTION TO ALGORITHMS

33. Computational Geometry

33.3 Finding the convex hull

33.4 Finding the closest pair of points

2011.5.26

関根 渓 (情報知識ネットワーク研究室 B4)

CONTENTS

33.3 凸包の構成

(Finding the convex hull)

33.4 最近点対の発見

(Finding the pair of closest points)

CONTENTS

33.3 凸包の構成 (Finding the convex hull)

凸包(convex hull)とは?

凸包を計算するアルゴリズム

凸包(convex hull)とは?

点集合Qの凸包とは、Qの各点がその境界上にあるような最小の凸多角形Pのこと

Qの凸包をCH(Q)と表現

p1

p0

p12

p10

p3 p11

p9

p7

p8 p6 p5

p4

p2

直感的には・・・ 集合の各点を板から飛び出ている釘とし、

それら全ての釘を取り囲むきつい輪ゴムが作る形状が凸包

点集合Qとその凸包 CH(Q)

Q={p0,p1,p2,…,p12}

凸包(convex hull)とは?

p1

p0

p12

p10

p3

p11

p9

p7

p8 p6 p5

p4

p2

Q={p0,p1,p2,…,p12}

例1:境界線外に点が存在

p1

p0

p12

p10

p3

p11

p9

p7

p8

p6

p5

p4

p2

例2:凸多角形ではない

凸包ではない例

CONTENTS

33.3 凸包の構成 (Finding the convex hull)

凸包(convex hull)とは?

凸包を計算するアルゴリズム

凸包を計算するアルゴリズム

凸包を計算する様々なアルゴリズムの紹介

1. 逐次添加法 (incremental method)

2. 分割統治法 (divided-and-conquer method)

3. 枝刈り探索法 (prune-and-search method)

4. Graham スキャン (Graham’s scan)

5. Jarvis の行進法 (Jarvis’s march)

凸包を計算するアルゴリズム 逐次添加法 (incremental method)

点を左から右の順にソートし、ソート列<p0,p1,…,pn>求める.

i番目の段階で,左からi-1個目の凸包CH({p0,p1,…,pi})を作る.

実行時間はO(nlogn)である.

イメージとしては・・・

p1

p2

p6

p7 p5

p4

p3 p0

i=2

Q={p0,p1,p2,…,p12}

p0

p1

p2

stack

CH({p0,p1,…,pi})の頂点がスタックに積まれていく

凸包を構成する点は最小で3点(三角形)なので,

最初はp1,p2,p3がPUSHされる

凸包を計算するアルゴリズム 逐次添加法 (incremental method)

点を左から右の順にソートし、ソート列<p0,p1,…,pn>求める.

i番目の段階で,左からi-1個目の凸包CH({p0,p1,…,pi})を作る.

実行時間はO(nlogn)である.

イメージとしては・・・

p1

p2

p6

p7 p5

p4

p3 p0

i=3

Q={p0,p1,p2,…,p12}

p0

p1

p2

stack

p3とCH({p0,p1,…,p2})の接線を求め,

CH({p0,p1,…,p3})の辺とし,

辺に挟まれる境界線を取り除く

この手続きをスタックの命令で表すと,水平軸方向において,接点と参照点の間にある点全てをスタックからPOPし,参照点をPUSHする,ということになる

凸包を計算するアルゴリズム 逐次添加法 (incremental method)

点を左から右の順にソートし、ソート列<p0,p1,…,pn>求める.

i番目の段階で,左からi-1個目の凸包CH({p0,p1,…,pi})を作る.

実行時間はO(nlogn)である.

イメージとしては・・・

p1 p6

p7 p0

Q={p0,p1,p2,…,p12}

p0

p1

p2

stack

p2

p5

p4

p3

i=3

p3

p3がPUSHされる

凸包を計算するアルゴリズム 逐次添加法 (incremental method)

点を左から右の順にソートし、ソート列<p0,p1,…,pn>求める.

i番目の段階で,左からi-1個目の凸包CH({p0,p1,…,pi})を作る.

実行時間はO(nlogn)である.

イメージとしては・・・

p1 p6

p7 p0

Q={p0,p1,p2,…,p12}

p0

p1

p2

stack

p2

p5

p4

p3

i=3

p3

p4とCH({p0,p1,…,p3})の接線を求め,

CH({p0,p1,…,p4})の辺とし,

辺に挟まれる境界線を取り除く

凸包を計算するアルゴリズム 1. 逐次添加法 (incremental method)

点を左から右の順にソートし、ソート列<p0,p1,…,pn>求める.

i番目の段階で,左からi-1個目の凸包CH({p0,p1,…,pi})を作る.

実行時間はO(nlogn)である.

イメージとしては・・・

p1 p6

p7 p0

Q={p0,p1,p2,…,p12}

p0

p1

p2

stack

p2

p5

p4

p3

i=4

p3

p4

p4がPUSHされる

凸包を計算するアルゴリズム 1. 逐次添加法 (incremental method)

点を左から右の順にソートし、ソート列<p0,p1,…,pn>求める.

i番目の段階で,左からi-1個目の凸包CH({p0,p1,…,pi})を作る.

実行時間はO(nlogn)である.

イメージとしては・・・

p1 p6

p7 p0

Q={p0,p1,p2,…,p12}

p0

p1

p2

stack

p2

p5

p4 p3

i=5

p3

p4

p5とCH({p0,p1,…,p4})の接線を求め,

CH({p0,p1,…,p5})の辺とし,

辺に挟まれる境界線を取り除く

凸包を計算するアルゴリズム 逐次添加法 (incremental method)

点を左から右の順にソートし、ソート列<p0,p1,…,pn>求める.

i番目の段階で,左からi-1個目の凸包CH({p0,p1,…,pi})を作る.

実行時間はO(nlogn)である.

イメージとしては・・・

p1 p6

p7 p0

Q={p0,p1,p2,…,p12}

p0

p1

p2

stack

p2

p5

p4 p3

i=5

p5

境界線上の点であるp3とp4がPOPされ,

p5がPUSHされる

凸包を計算するアルゴリズム 逐次添加法 (incremental method)

点を左から右の順にソートし、ソート列<p0,p1,…,pn>求める.

i番目の段階で,左からi-1個目の凸包CH({p0,p1,…,pi})を作る.

実行時間はO(nlogn)である.

イメージとしては・・・

p1

p6

p7 p0

Q={p0,p1,p2,…,p12}

p0

p1

p2

stack

p2

p5

p4 p3

i=6

p5

p6とCH({p0,p1,…,p5})の接線を求め,

CH({p0,p1,…,p6})の辺とし,

辺に挟まれる境界線を取り除く

凸包を計算するアルゴリズム 逐次添加法 (incremental method)

点を左から右の順にソートし、ソート列<p0,p1,…,pn>求める.

i番目の段階で,左からi-1個目の凸包CH({p0,p1,…,pi})を作る.

実行時間はO(nlogn)である.

イメージとしては・・・

p1 p6

p7 p0

Q={p0,p1,p2,…,p12}

p0

p1

p2

stack

p2

p5

p4 p3

i=6

p6

境界線上の点であるp5がPOPされ,

p6がPUSHされる

凸包を計算するアルゴリズム 逐次添加法 (incremental method)

点を左から右の順にソートし、ソート列<p0,p1,…,pn>求める.

i番目の段階で,左からi-1個目の凸包CH({p0,p1,…,pi})を作る.

実行時間はO(nlogn)である.

イメージとしては・・・

p1 p6

p7 p0

Q={p0,p1,p2,…,p12}

p0

p1

p2

stack

p2

p5

p4 p3

i=7

p6

p7とCH({p0,p1,…,p6})の接線を求め,

CH({p0,p1,…,p7})の辺とし,

辺に挟まれる境界線を取り除く

凸包を計算するアルゴリズム 逐次添加法 (incremental method)

点を左から右の順にソートし、ソート列<p0,p1,…,pn>求める.

i番目の段階で,左からi-1個目の凸包CH({p0,p1,…,pi})を作る.

実行時間はO(nlogn)である.

イメージとしては・・・

p1

p0

Q={p0,p1,p2,…,p12}

p0

p1

p2

stack

p7 p2

p6

p5

p4

p3

i=7

p7

p7がPUSHされて、処理が終了

p6

凸包を計算するアルゴリズム 逐次添加法 (incremental method)

点を左から右の順にソートし、ソート列<p0,p1,…,pn>求める.

i番目の段階で,左からi-1個目の凸包CH({p0,p1,…,pi})を作る.

実行時間はO(nlogn)である.

イメージとしては・・・

p1

p0

Q={p0,p1,p2,…,p12}

p0

p1

p2

stack

p7 p2

p6

p5

p4

p3

i=7

p7

p7がPUSHされて、処理が終了

p6

大きな問題点が発生!!

凸包を計算するアルゴリズム 逐次添加法 (incremental method)

その問題点とは?

スタックに積まれている点は,それが凸包の頂点であるということしか表していない

→つまりどの点とどの点を結べば凸包が作れるのかわからない

そこで、解決法として以下のような技法が挙げられる

p1

p0

p2

p6

p5

p4

p3

p7 線分p0p7

線分p0p7を境界線として点集合を二つの部分集合に分割,それぞれの部分集合に対する凸包

(上部凸包、下部凸包)を逐次添加法で求める

上部凸包の頂点を含むスタックをS1

下部凸包の頂点を含むスタックをS2

とすると,

これらは水平座標について左から右の順に頂点を含んでいるため,S2を逆順にソートしたものをS1と

組み合わせて出力すれば,凸包の頂点が時計回りに出力されることとなる

赤線:上部凸包

黄線:下部凸包

凸包を計算するアルゴリズム 逐次添加法 (incremental method)

接点の選び方

接点はその時凸包の頂点となっている点のうちのどれかである

スタックに積まれている順にそれが接点であるかを調べていく

例:

p1 p6

p0

p2

p5

p4 p3

i=5

p0

p1

p2

stack

p3

p4

1

2

3

4

1

4 p7 2

3 接点ではないのでスタックからPOP

接点ではないのでスタックからPOP

接点なのでそのまま

接点なのでそのまま

一度スタックにPUSHされた点がPOPされるのは高々1回であるから,

アルゴリズム全体のPOPの回数はn-3回未満である

→つまり凸包の更新は全体で n-3(POP回数)+2n(接点の選択)=O(n)時間しかかからない

凸包を計算するアルゴリズム 逐次添加法 (incremental method)

計算量の吟味

凸包の更新には全体で O(n) (前項より)

左から右の順に点をソートするのに O(nlogn) (マージソート等)

PUSH命令には O(n)

したがって,逐次添加法の計算量はソーティングに依存することとなり,

全体で O(nlogn) となる

以上から,

Exercise 33.3-6 ★

逐次添加法を用いてn点の凸包をO(nlogn)時間で計算する方法を示せ.

は示された.

凸包を計算するアルゴリズム 分割統治法 (divide-and-conquer method)

Θ(n)時間でn点の集合を,左から 𝑛/2 個の点からなる集合と右から 𝑛/2個の点からなる集合の2つに分割し,これらの部分集合の凸包を再帰的に計算し,巧妙な方法を用いてこれらの凸包をO(n)時間で統合する.

イメージ的には・・・

凸包を計算するアルゴリズム 分割統治法 (divide-and-conquer method)

Θ(n)時間でn点の集合を,左から 𝑛/2 個の点からなる集合と右から 𝑛/2個の点からなる集合の2つに分割し,これらの部分集合の凸包を再帰的に計算し,巧妙な方法を用いてこれらの凸包をO(n)時間で統合する.

イメージ的には・・・

1 n点の集合を2つの部分集合に分割

凸包を計算するアルゴリズム 分割統治法 (divide-and-conquer method)

Θ(n)時間でn点の集合を,左から 𝑛/2 個の点からなる集合と右から 𝑛/2個の点からなる集合の2つに分割し,これらの部分集合の凸包を再帰的に計算し,巧妙な方法を用いてこれらの凸包をO(n)時間で統合する.

イメージ的には・・・

1 2

凸包を計算するアルゴリズム 分割統治法 (divide-and-conquer method)

Θ(n)時間でn点の集合を,左から 𝑛/2 個の点からなる集合と右から 𝑛/2個の点からなる集合の2つに分割し,これらの部分集合の凸包を再帰的に計算し,巧妙な方法を用いてこれらの凸包をO(n)時間で統合する.

1 2 3

凸包を計算するアルゴリズム 分割統治法 (divide-and-conquer method)

Θ(n)時間でn点の集合を,左から 𝑛/2 個の点からなる集合と右から 𝑛/2個の点からなる集合の2つに分割し,これらの部分集合の凸包を再帰的に計算し,巧妙な方法を用いてこれらの凸包をO(n)時間で統合する.

1 2 3

凸包を計算するアルゴリズム 分割統治法 (divide-and-conquer method)

Θ(n)時間でn点の集合を,左から 𝑛/2 個の点からなる集合と右から 𝑛/2個の点からなる集合の2つに分割し,これらの部分集合の凸包を再帰的に計算し,巧妙な方法を用いてこれらの凸包をO(n)時間で統合する.

1 2 3

凸包を計算するアルゴリズム 分割統治法 (divide-and-conquer method)

Θ(n)時間でn点の集合を,左から 𝑛/2 個の点からなる集合と右から 𝑛/2個の点からなる集合の2つに分割し,これらの部分集合の凸包を再帰的に計算し,巧妙な方法を用いてこれらの凸包をO(n)時間で統合する.

1 2 3 2つの凸包(または直線)

の上部接線を求め、

それらを辺として一つに統合する

凸包を計算するアルゴリズム 分割統治法 (divide-and-conquer method)

Θ(n)時間でn点の集合を,左から 𝑛/2 個の点からなる集合と右から 𝑛/2個の点からなる集合の2つに分割し,これらの部分集合の凸包を再帰的に計算し,巧妙な方法を用いてこれらの凸包をO(n)時間で統合する.

1 2 3 2つの凸包(または直線)

の上部接線を求め、

それらを辺として一つに統合する

凸包を計算するアルゴリズム 分割統治法 (divide-and-conquer method)

Θ(n)時間でn点の集合を,左から 𝑛/2 個の点からなる集合と右から 𝑛/2個の点からなる集合の2つに分割し,これらの部分集合の凸包を再帰的に計算し,巧妙な方法を用いてこれらの凸包をO(n)時間で統合する.

1 2 3 4

凸包を計算するアルゴリズム 分割統治法 (divide-and-conquer method)

Θ(n)時間でn点の集合を,左から 𝑛/2 個の点からなる集合と右から 𝑛/2個の点からなる集合の2つに分割し,これらの部分集合の凸包を再帰的に計算し,巧妙な方法を用いてこれらの凸包をO(n)時間で統合する.

1 2 3 4

凸包を計算するアルゴリズム 分割統治法 (divide-and-conquer method)

Θ(n)時間でn点の集合を,左から 𝑛/2 個の点からなる集合と右から 𝑛/2個の点からなる集合の2つに分割し,これらの部分集合の凸包を再帰的に計算し,巧妙な方法を用いてこれらの凸包をO(n)時間で統合する.

1 2 3 4

凸包を計算するアルゴリズム 分割統治法 (divide-and-conquer method)

Θ(n)時間でn点の集合を,左から 𝑛/2 個の点からなる集合と右から 𝑛/2個の点からなる集合の2つに分割し,これらの部分集合の凸包を再帰的に計算し,巧妙な方法を用いてこれらの凸包をO(n)時間で統合する.

1 2 3 4

凸包を計算するアルゴリズム 分割統治法 (divide-and-conquer method)

Θ(n)時間でn点の集合を,左から 𝑛/2 個の点からなる集合と右から 𝑛/2個の点からなる集合の2つに分割し,これらの部分集合の凸包を再帰的に計算し,巧妙な方法を用いてこれらの凸包をO(n)時間で統合する.

1 2 3 4

凸包を計算するアルゴリズム 分割統治法 (divide-and-conquer method)

Θ(n)時間でn点の集合を,左から 𝑛/2 個の点からなる集合と右から 𝑛/2個の点からなる集合の2つに分割し,これらの部分集合の凸包を再帰的に計算し,巧妙な方法を用いてこれらの凸包をO(n)時間で統合する.

1 2 3 4

凸包を計算するアルゴリズム 分割統治法 (divide-and-conquer method)

Θ(n)時間でn点の集合を,左から 𝑛/2 個の点からなる集合と右から 𝑛/2個の点からなる集合の2つに分割し,これらの部分集合の凸包を再帰的に計算し,巧妙な方法を用いてこれらの凸包をO(n)時間で統合する.

1 2 3 4

凸包を計算するアルゴリズム 分割統治法 (divide-and-conquer method)

Θ(n)時間でn点の集合を,左から 𝑛/2 個の点からなる集合と右から 𝑛/2個の点からなる集合の2つに分割し,これらの部分集合の凸包を再帰的に計算し,巧妙な方法を用いてこれらの凸包をO(n)時間で統合する.

1 2 3 4 5

凸包を計算するアルゴリズム 分割統治法 (divide-and-conquer method)

Θ(n)時間でn点の集合を,左から 𝑛/2 個の点からなる集合と右から 𝑛/2個の点からなる集合の2つに分割し,これらの部分集合の凸包を再帰的に計算し,巧妙な方法を用いてこれらの凸包をO(n)時間で統合する.

1 2 3 4 5 6

凸包を計算するアルゴリズム 分割統治法 (divide-and-conquer method)

Θ(n)時間でn点の集合を,左から 𝑛/2 個の点からなる集合と右から 𝑛/2個の点からなる集合の2つに分割し,これらの部分集合の凸包を再帰的に計算し,巧妙な方法を用いてこれらの凸包をO(n)時間で統合する.

1 2 3 4 5 6

凸包を計算するアルゴリズム 分割統治法 (divide-and-conquer method)

Θ(n)時間でn点の集合を,左から 𝑛/2 個の点からなる集合と右から 𝑛/2個の点からなる集合の2つに分割し,これらの部分集合の凸包を再帰的に計算し,巧妙な方法を用いてこれらの凸包をO(n)時間で統合する.

1 2 3 4 5 6

凸包を計算するアルゴリズム 分割統治法 (divide-and-conquer method)

Θ(n)時間でn点の集合を,左から 𝑛/2 個の点からなる集合と右から 𝑛/2個の点からなる集合の2つに分割し,これらの部分集合の凸包を再帰的に計算し,巧妙な方法を用いてこれらの凸包をO(n)時間で統合する.

1 2 3 4 5 6

凸包を計算するアルゴリズム 分割統治法 (divide-and-conquer method)

Θ(n)時間でn点の集合を,左から 𝑛/2 個の点からなる集合と右から 𝑛/2個の点からなる集合の2つに分割し,これらの部分集合の凸包を再帰的に計算し,巧妙な方法を用いてこれらの凸包をO(n)時間で統合する.

1 2 3 4 5 6

凸包を計算するアルゴリズム 分割統治法 (divide-and-conquer method)

Θ(n)時間でn点の集合を,左から 𝑛/2 個の点からなる集合と右から 𝑛/2個の点からなる集合の2つに分割し,これらの部分集合の凸包を再帰的に計算し,巧妙な方法を用いてこれらの凸包をO(n)時間で統合する.

1 2 3 4 5 6 7

凸包を計算するアルゴリズム 分割統治法 (divide-and-conquer method)

Θ(n)時間でn点の集合を,左から 𝑛/2 個の点からなる集合と右から 𝑛/2個の点からなる集合の2つに分割し,これらの部分集合の凸包を再帰的に計算し,巧妙な方法を用いてこれらの凸包をO(n)時間で統合する.

1 2 3 4 5 6 7

凸包を計算するアルゴリズム 分割統治法 (divide-and-conquer method)

Θ(n)時間でn点の集合を,左から 𝑛/2 個の点からなる集合と右から 𝑛/2個の点からなる集合の2つに分割し,これらの部分集合の凸包を再帰的に計算し,巧妙な方法を用いてこれらの凸包をO(n)時間で統合する.

1 2 3 4 5 6 7

凸包を計算するアルゴリズム 分割統治法 (divide-and-conquer method)

Θ(n)時間でn点の集合を,左から 𝑛/2 個の点からなる集合と右から 𝑛/2個の点からなる集合の2つに分割し,これらの部分集合の凸包を再帰的に計算し,巧妙な方法を用いてこれらの凸包をO(n)時間で統合する.

1 2 3 4 5 6 7

凸包を計算するアルゴリズム 分割統治法 (divide-and-conquer method)

Θ(n)時間でn点の集合を,左から 𝑛/2 個の点からなる集合と右から 𝑛/2個の点からなる集合の2つに分割し,これらの部分集合の凸包を再帰的に計算し,巧妙な方法を用いてこれらの凸包をO(n)時間で統合する.

1 2 3 4 5 6 7

凸包を計算するアルゴリズム 分割統治法 (divide-and-conquer method)

Θ(n)時間でn点の集合を,左から 𝑛/2 個の点からなる集合と右から 𝑛/2個の点からなる集合の2つに分割し,これらの部分集合の凸包を再帰的に計算し,巧妙な方法を用いてこれらの凸包をO(n)時間で統合する.

1 2 3 4 5 6 7

凸包を計算するアルゴリズム 分割統治法 (divide-and-conquer method)

Θ(n)時間でn点の集合を,左から 𝑛/2 個の点からなる集合と右から 𝑛/2個の点からなる集合の2つに分割し,これらの部分集合の凸包を再帰的に計算し,巧妙な方法を用いてこれらの凸包をO(n)時間で統合する.

1 2 3 4 5 6 7

凸包を計算するアルゴリズム 分割統治法 (divide-and-conquer method)

Θ(n)時間でn点の集合を,左から 𝑛/2 個の点からなる集合と右から 𝑛/2個の点からなる集合の2つに分割し,これらの部分集合の凸包を再帰的に計算し,巧妙な方法を用いてこれらの凸包をO(n)時間で統合する.

1 2 3 4 5 6 7

凸包を計算するアルゴリズム 分割統治法 (divide-and-conquer method)

Θ(n)時間でn点の集合を,左から 𝑛/2 個の点からなる集合と右から 𝑛/2個の点からなる集合の2つに分割し,これらの部分集合の凸包を再帰的に計算し,巧妙な方法を用いてこれらの凸包をO(n)時間で統合する.

1 2 3 4 5 6 7

凸包を計算するアルゴリズム 分割統治法 (divide-and-conquer method)

Θ(n)時間でn点の集合を,左から 𝑛/2 個の点からなる集合と右から 𝑛/2個の点からなる集合の2つに分割し,これらの部分集合の凸包を再帰的に計算し,巧妙な方法を用いてこれらの凸包をO(n)時間で統合する.

凸包を計算するアルゴリズム 分割統治法 (divide-and-conquer method)

上部接線の求め方

q1

q2

q3

q4

q5

r5

r4

r3

r2

r1

r6

左の凸包の最右点q3

右の凸包の最左点r5

を線で結ぶ

Us:線分(q3,r5)とすると

Usは

r5において接線である

q3において接線ではない

Us:線分(q4,r5)とする

凸包を計算するアルゴリズム 分割統治法 (divide-and-conquer method)

上部接線の求め方

q1

q2

q3

q4

q5

r5

r4

r3

r2

r1

r6

Us:線分(q4,r5)とすると

Usは

q4において接線である

r5において接線ではない

Us:線分(q4,r4)とする

凸包を計算するアルゴリズム 分割統治法 (divide-and-conquer method)

上部接線の求め方

q1

q2

q3

q4

q5

r5

r4

r3

r2

r1

r6

Us:線分(q4,r4)とすると

Usは

q4において接線である

r5において接線ではない

Us:線分(q4,r3)とする

凸包を計算するアルゴリズム 分割統治法 (divide-and-conquer method)

上部接線の求め方

q1

q2

q3

q4

q5

r5

r4

r3

r2

r1

r6

Us:線分(q4,r3)とすると

Usは

q4において接線である(傾きUs>直線q4q5)

r3において接線である(傾きUs直線>r3r2)

よってq4r3は上部接線であり,凸包の辺

凸包を計算するアルゴリズム 分割統治法 (divide-and-conquer method)

下部接線の求め方

q1

q2

q3

q4

q5

r5

r4

r3

r2

r1

r6

上部接線を求めた方法で、下方向に頂点を辿ることで求まる

凸包を計算するアルゴリズム 枝刈り探索法 (prune-and-search method)

9.3節の最悪線形時間の中央値発見アルゴリズムとよく似ている.

凸包の上側部分(上部チェイン)だけが残るまで残りの点のうちの一定割合を 繰り返し捨てることによって凸包の上側部分を求める.

次に,同じ方法で下部チェインを求める.

凸包がh個の頂点を含んでいるとき、O(nlogh)時間しかかからない.

p1

p0

p10

p3 p11 p9

p7

p8 p6 p5

p4

p2

点集合Qとその凸包 CH(Q)

Q={p0,p1,p2,…,p12}

p12

赤線:上部チェイン

黄線:下部チェイン

凸包を計算するということ

計算幾何問題には凸包の計算から始めるものが多い

例:最遠点対 (farthest pair problem)

→平面上の n点集合が与えられたときの互いの距離が最大となるような2点のこと

→これら2点は必ず凸包の頂点となる(練習問題33.3-3より)

凸包を計算するアルゴリズム

n点集合

凸包を計算するということ

計算幾何問題には凸包の計算から始めるものが多い

例:最遠点対 (farthest pair problem)

→平面上の n点集合が与えられたときの互いの距離が最大となるような2点のこと

→これら2点は必ず凸包の頂点となる(練習問題33.3-3より)

証明は省くが,凸n角形の最遠点対は O(n)時間で計算可能

→n個の入力点の凸包を O(nlogn)時間で計算し,求められた凸多角形の頂点の最遠点を求めれば,任意の n点集合の最遠点対を O(nlogn)時間で計算できる

凸包を計算するアルゴリズム

n点集合

最遠点対

凸包を計算するアルゴリズム

これから紹介するアルゴリズムについて

Graham スキャン (Graham’s scan)

実行時間:O(nlogn)

Jarvis の行進法 (Jarvis’s march)

実行時間:O(nh) (ただし、hは凸包の頂点数)

Qの頂点のうちどれを凸包の頂点として持つか、どれを捨てるかを判定する

凸包の頂点を反時計回りの順に出力

ある参照点に関する偏角順に点を処理する、“回転走査”と呼ばれる技法を用いる

凸包を計算するアルゴリズム

回転走査

ある参照点についての偏角の順に点を処理する

参照点 p

1

凸包を計算するアルゴリズム

回転走査

ある参照点についての偏角の順に点を処理する

参照点 p

2

凸包を計算するアルゴリズム

回転走査

ある参照点についての偏角の順に点を処理する

参照点 p

3

凸包を計算するアルゴリズム

回転走査

ある参照点についての偏角の順に点を処理する

参照点 p

4

凸包を計算するアルゴリズム

回転走査

ある参照点についての偏角の順に点を処理する

参照点 p

5

凸包を計算するアルゴリズム

回転走査

ある参照点についての偏角の順に点を処理する

参照点 p

6

凸包を計算するアルゴリズム

回転走査

ある参照点についての偏角の順に点を処理する

参照点 p

7

凸包を計算するアルゴリズム Graham スキャン (Graham’s scan)

候補点をスタックSで管理しながら凸包問題を解く

入力集合Qの各点はいったんスタックに入れられ,CH(Q)の頂点でない点は最終的にはスタックから取り除かれる

アルゴリズム終了の時点で,スタックはCH(Q)の頂点だけを,境界面上での反時計回りの出現順に含む

p1

p0

入力集合 Q={p0,p1,p2,…,p12}

p2

p6

p5

p4

p3 p7

p0

stack

Graham’s scan 終了時のスタック

p1

p2

p6

p7

凸包を計算するアルゴリズム Graham スキャン (Graham’s scan)

手続き GRAHAM-SCAN

入力: 点集合Q ただし |Q|≧3

TOP(S):スタックSの一番上の点を返す関数

NEXT-TO-TOP(S):スタックSの上から二番目の点を返す関数

アルゴリズム

GRAHAM-SCAN(Q)

1 let 𝑝0 be the point in Q with the minimum y-coordinate,

or the leftmost such point in case of a tie

2 let <𝑝1, 𝑝2, … , 𝑝𝑚> be the remaining points in Q,

sorted by polar angle in counterclockwise order around 𝑝0 (if more than one point has the same angle, remove all but

the one that is farthest from 𝑝0)

3 PUSH(𝑝0,S)

4 PUSH(𝑝1,S)

5 PUSH(𝑝2,S)

6 for i ← 3 to m

7 do while the angle formed by points NEXT-TO-TOP(S), TOP(S), and 𝑝𝑖 makes nonleft turn

8 do POP(S)

9 PUSH(𝑝𝑖, S)

10 return S

Line 1

集合Qのy座標最小の点をp0とする

複数あれば最左のものをp0とする

凸包を計算するアルゴリズム Graham スキャン (Graham’s scan)

手続き GRAHAM-SCAN

入力: 点集合Q ただし |Q|≧3

TOP(S):スタックSの一番上の点を返す関数

NEXT-TO-TOP(S):スタックSの上から二番目の点を返す関数

アルゴリズム

GRAHAM-SCAN(Q)

1 let 𝑝0 be the point in Q with the minimum y-coordinate,

or the leftmost such point in case of a tie

2 let <𝑝1, 𝑝2, … , 𝑝𝑚> be the remaining points in Q,

sorted by polar angle in counterclockwise order around 𝑝0 (if more than one point has the same angle, remove all but

the one that is farthest from 𝑝0)

3 PUSH(𝑝0,S)

4 PUSH(𝑝1,S)

5 PUSH(𝑝2,S)

6 for i ← 3 to m

7 do while the angle formed by points NEXT-TO-TOP(S), TOP(S), and 𝑝𝑖 makes nonleft turn

8 do POP(S)

9 PUSH(𝑝𝑖, S)

10 return S

Line 2

Qの残りの点をp0の周りの反時計回りの偏角順にソートしたものを<p1,p2,….,pm> とする

複数の点が同じ偏角をもつときはp0から最遠となるもの以外は取り除く

凸包を計算するアルゴリズム Graham スキャン (Graham’s scan)

手続き GRAHAM-SCAN

入力: 点集合Q ただし |Q|≧3

TOP(S):スタックSの一番上の点を返す関数

NEXT-TO-TOP(S):スタックSの上から二番目の点を返す関数

アルゴリズム

GRAHAM-SCAN(Q)

1 let 𝑝0 be the point in Q with the minimum y-coordinate,

or the leftmost such point in case of a tie

2 let <𝑝1, 𝑝2, … , 𝑝𝑚> be the remaining points in Q,

sorted by polar angle in counterclockwise order around 𝑝0 (if more than one point has the same angle, remove all but

the one that is farthest from 𝑝0)

3 PUSH(𝑝0,S)

4 PUSH(𝑝1,S)

5 PUSH(𝑝2,S)

6 for i ← 3 to m

7 do while the angle formed by points NEXT-TO-TOP(S), TOP(S), and 𝑝𝑖 makes nonleft turn

8 do POP(S)

9 PUSH(𝑝𝑖, S)

10 return S

Line 3-5

p0,p1,p2をスタックにPUSH

凸包を計算するアルゴリズム Graham スキャン (Graham’s scan)

手続き GRAHAM-SCAN

入力: 点集合Q ただし |Q|≧3

TOP(S):スタックSの一番上の点を返す関数

NEXT-TO-TOP(S):スタックSの上から二番目の点を返す関数

アルゴリズム

GRAHAM-SCAN(Q)

1 let 𝑝0 be the point in Q with the minimum y-coordinate,

or the leftmost such point in case of a tie

2 let <𝑝1, 𝑝2, … , 𝑝𝑚> be the remaining points in Q,

sorted by polar angle in counterclockwise order around 𝑝0 (if more than one point has the same angle, remove all but

the one that is farthest from 𝑝0)

3 PUSH(𝑝0,S)

4 PUSH(𝑝1,S)

5 PUSH(𝑝2,S)

6 for i ← 3 to m

7 do while the angle formed by points NEXT-TO-TOP(S), TOP(S), and 𝑝𝑖 makes nonleft turn

8 do POP(S)

9 PUSH(𝑝𝑖, S)

10 return S

Line 6-9 for ループ

部分列 <p3,p4,….,pm> の各点について一度ずつ繰り返す

目的は,点piを処理した後,スタックSが底から先頭に向けて CH({p0,p1,…,p12}) の頂点を反時計周りの順に含むようにすること

凸包を計算するアルゴリズム Graham スキャン (Graham’s scan)

手続き GRAHAM-SCAN

入力: 点集合Q ただし |Q|≧3

TOP(S):スタックSの一番上の点を返す関数

NEXT-TO-TOP(S):スタックSの上から二番目の点を返す関数

アルゴリズム

GRAHAM-SCAN(Q)

1 let 𝑝0 be the point in Q with the minimum y-coordinate,

or the leftmost such point in case of a tie

2 let <𝑝1, 𝑝2, … , 𝑝𝑚> be the remaining points in Q,

sorted by polar angle in counterclockwise order around 𝑝0 (if more than one point has the same angle, remove all but

the one that is farthest from 𝑝0)

3 PUSH(𝑝0,S)

4 PUSH(𝑝1,S)

5 PUSH(𝑝2,S)

6 for i ← 3 to m

7 do while the angle formed by points NEXT-TO-TOP(S), TOP(S), and 𝑝𝑖 makes nonleft turn

8 do POP(S)

9 PUSH(𝑝𝑖, S)

10 return S

Line 7-8 while ループ

凸包の頂点を形成しないことがわかったときに,そのような点をスタックから取り除く

凸包を反時計回りに回るとき,各頂点で左に曲がるはず

ループで左折しない点を見つけたら,その度に頂点をスタックから取り除く

凸包を計算するアルゴリズム Graham スキャン (Graham’s scan)

手続き GRAHAM-SCAN

入力: 点集合Q ただし |Q|≧3

TOP(S):スタックSの一番上の点を返す関数

NEXT-TO-TOP(S):スタックSの上から二番目の点を返す関数

アルゴリズム

GRAHAM-SCAN(Q)

1 let 𝑝0 be the point in Q with the minimum y-coordinate,

or the leftmost such point in case of a tie

2 let <𝑝1, 𝑝2, … , 𝑝𝑚> be the remaining points in Q,

sorted by polar angle in counterclockwise order around 𝑝0 (if more than one point has the same angle, remove all but

the one that is farthest from 𝑝0)

3 PUSH(𝑝0,S)

4 PUSH(𝑝1,S)

5 PUSH(𝑝2,S)

6 for i ← 3 to m

7 do while the angle formed by points NEXT-TO-TOP(S), TOP(S), and 𝑝𝑖 makes nonleft turn

8 do POP(S)

9 PUSH(𝑝𝑖, S)

10 return S

凸包を計算するアルゴリズム Graham スキャン (Graham’s scan)

動作例

入力集合Q(未ソート)

凸包を計算するアルゴリズム Graham スキャン (Graham’s scan)

動作例

p0

集合Qに含まれる点のうち,

y座標の最も小さい点をp0とする

凸包を計算するアルゴリズム Graham スキャン (Graham’s scan)

動作例

p0

p9

p2

p11

p12

p8

p7 p6 p5

p4

p10

p1

p3

P0に対する偏角の順に残りの点をソートする

凸包を計算するアルゴリズム Graham スキャン (Graham’s scan)

動作例

p0

p9

p2

p11

p12 p8

p7

p6 p5

p4

p10

p1

p3

p0,p1,p2をSにPUSH

p0

stack S

p1

p2

凸包を計算するアルゴリズム Graham スキャン (Graham’s scan)

動作例

p0

p9

p2

p11

p12 p8

p7

p6 p5

p4

p10

p1

p3

i=3

NEXT-TO-TOP(S)=p1

TOP(S)=p2

pi=p3

∠p1p2p3は右回り

p2をPOP

p0

stack S

p1

p2

凸包を計算するアルゴリズム Graham スキャン (Graham’s scan)

動作例

p0

p9

p2

p11

p12 p8

p7

p6 p5

p4

p10

p1

p3

i=3

NEXT-TO-TOP(S)=p1

TOP(S)=p2

pi=p3

∠p1p2p3は右回り

p2をPOP

p0

stack S

p1

凸包を計算するアルゴリズム Graham スキャン (Graham’s scan)

動作例

p0

p9

p2

p11

p12 p8

p7

p6 p5

p4

p10

p1

p3

i=3

NEXT-TO-TOP(S)=p0

TOP(S)=p1

pi=p3

∠p0p1p3は左回り

p3をPUSH

p0

stack S

p1

凸包を計算するアルゴリズム Graham スキャン (Graham’s scan)

動作例

p0

p9

p2

p11

p12 p8

p7

p6 p5

p4

p10

p1

p3

i=3

NEXT-TO-TOP(S)=p0

TOP(S)=p1

pi=p3

∠p0p1p3は左回り

p3をPUSH

p0

stack S

p1

p3

凸包を計算するアルゴリズム Graham スキャン (Graham’s scan)

動作例

p0

p9

p2

p11

p12 p8

p7

p6 p5

p4

p10

p1

p3

i=4

NEXT-TO-TOP(S)=p1

TOP(S)=p3

pi=p4

∠p1p3p4は左回り

p4をPUSH

p0

stack S

p1

p3

凸包を計算するアルゴリズム Graham スキャン (Graham’s scan)

動作例

p0

p9

p2

p11

p12 p8

p7

p6 p5

p4

p10

p1

p3

i=4

NEXT-TO-TOP(S)=p1

TOP(S)=p3

pi=p4

∠p1p3p4は左回り

p4をPUSH

p0

stack S

p1

p3

p4

凸包を計算するアルゴリズム Graham スキャン (Graham’s scan)

動作例

p0

p9

p2

p11

p12 p8

p7

p6

p5

p4

p10

p1

p3

i=5

NEXT-TO-TOP(S)=p3

TOP(S)=p4

pi=p5

∠p3p4p5は右回り

p4をPOP

p0

stack S

p1

p3

p4

凸包を計算するアルゴリズム Graham スキャン (Graham’s scan)

動作例

p0

p9

p2

p11

p12 p8

p7

p6

p5

p4

p10

p1

p3

i=5

NEXT-TO-TOP(S)=p3

TOP(S)=p4

pi=p5

∠p3p4p5は右回り

p4をPOP

p0

stack S

p1

p3

凸包を計算するアルゴリズム Graham スキャン (Graham’s scan)

動作例

p0

p9

p2

p11

p12 p8

p7

p6

p5

p4

p10

p1

p3

i=5

NEXT-TO-TOP(S)=p1

TOP(S)=p3

pi=p5

∠p1p3p5は左回り

p5をPUSH

p0

stack S

p1

p3

凸包を計算するアルゴリズム Graham スキャン (Graham’s scan)

動作例

p0

p9

p2

p11

p12 p8

p7

p6

p5

p4

p10

p1

p3

i=5

NEXT-TO-TOP(S)=p1

TOP(S)=p3

pi=p5

∠p1p3p5は左回り

p5をPUSH

p0

stack S

p1

p3

p5

凸包を計算するアルゴリズム Graham スキャン (Graham’s scan)

動作例

p0

p9

p2

p11

p12 p8

p7

p6

p5

p4

p10

p1

p3

i=6

NEXT-TO-TOP(S)=p3

TOP(S)=p5

pi=p6

∠p3p5p6は左回り

p6をPUSH

p0

stack S

p1

p3

p5

凸包を計算するアルゴリズム Graham スキャン (Graham’s scan)

動作例

p0

p9

p2

p11

p12 p8

p7

p6

p5

p4

p10

p1

p3

i=6

NEXT-TO-TOP(S)=p3

TOP(S)=p5

pi=p6

∠p3p5p6は左回り

p6をPUSH

p0

stack S

p1

p3

p5

p6

凸包を計算するアルゴリズム Graham スキャン (Graham’s scan)

動作例

p0

p9

p2

p11

p12 p8

p7

p6 p5

p4

p10

p1

p3

i=7

NEXT-TO-TOP(S)=p5

TOP(S)=p6

pi=p7

∠p5p6p7は左回り

p7をPUSH

p0

stack S

p1

p3

p5

p6

凸包を計算するアルゴリズム Graham スキャン (Graham’s scan)

動作例

p0

p9

p2

p11

p12 p8

p7

p6 p5

p4

p10

p1

p3

i=7

NEXT-TO-TOP(S)=p5

TOP(S)=p6

pi=p7

∠p5p6p7は左回り

p7をPUSH

p0

stack S

p1

p3

p5

p6

p7

凸包を計算するアルゴリズム Graham スキャン (Graham’s scan)

動作例

p0

p9

p2

p11

p12 p8

p7

p6 p5

p4

p10

p1

p3

i=8

NEXT-TO-TOP(S)=p6

TOP(S)=p7

pi=p8

∠p6p7p8は左回り

p8をPUSH

p0

stack S

p1

p3

p5

p6

p7

凸包を計算するアルゴリズム Graham スキャン (Graham’s scan)

動作例

p0

p9

p2

p11

p12 p8

p7

p6 p5

p4

p10

p1

p3

i=8

NEXT-TO-TOP(S)=p6

TOP(S)=p7

pi=p8

∠p6p7p8は左回り

p8をPUSH

p0

stack S

p1

p3

p5

p6

p7

p8

凸包を計算するアルゴリズム Graham スキャン (Graham’s scan)

動作例

p0

p9

p2

p11

p12 p8

p7

p6 p5

p4

p10

p1

p3

i=9

NEXT-TO-TOP(S)=p7

TOP(S)=p8

pi=p9

∠p7p8p9は右回り

p8をPOP

p0

stack S

p1

p3

p5

p6

p7

p8

凸包を計算するアルゴリズム Graham スキャン (Graham’s scan)

動作例

p0

p9

p2

p11

p12 p8

p7

p6 p5

p4

p10

p1

p3

i=9

NEXT-TO-TOP(S)=p7

TOP(S)=p8

pi=p9

∠p7p8p9は右回り

p8をPOP

p0

stack S

p1

p3

p5

p6

p7

凸包を計算するアルゴリズム Graham スキャン (Graham’s scan)

動作例

p0

p9

p2

p11

p12 p8

p7

p6 p5

p4

p10

p1

p3

i=9

NEXT-TO-TOP(S)=p6

TOP(S)=p7

pi=p9

∠p6p7p9は右回り

p7をPOP

p0

stack S

p1

p3

p5

p6

p7

凸包を計算するアルゴリズム Graham スキャン (Graham’s scan)

動作例

p0

p9

p2

p11

p12 p8

p7

p6 p5

p4

p10

p1

p3

i=9

NEXT-TO-TOP(S)=p6

TOP(S)=p7

pi=p9

∠p6p7p9は右回り

p7をPOP

p0

stack S

p1

p3

p5

p6

凸包を計算するアルゴリズム Graham スキャン (Graham’s scan)

動作例

p0

p9

p2

p11

p12 p8

p7

p6 p5

p4

p10

p1

p3

i=9

NEXT-TO-TOP(S)=p5

TOP(S)=p6

pi=p9

∠p5p6p9は右回り

p9をPUSH

p0

stack S

p1

p3

p5

p6

凸包を計算するアルゴリズム Graham スキャン (Graham’s scan)

動作例

p0

p9

p2

p11

p12 p8

p7

p6 p5

p4

p10

p1

p3

i=9

NEXT-TO-TOP(S)=p5

TOP(S)=p6

pi=p9

∠p5p6p9は右回り

p9をPUSH

p0

stack S

p1

p3

p5

p6

p9

凸包を計算するアルゴリズム Graham スキャン (Graham’s scan)

動作例

p0

p9

p2

p11

p12 p8

p7

p6 p5

p4

p10

p1

p3

i=10

NEXT-TO-TOP(S)=p6

TOP(S)=p9

pi=p10

∠p6p9p10は右回り

p9をPOP

p0

stack S

p1

p3

p5

p6

p9

凸包を計算するアルゴリズム Graham スキャン (Graham’s scan)

動作例

p0

p9

p2

p11

p12 p8

p7

p6 p5

p4

p10

p1

p3

i=10

NEXT-TO-TOP(S)=p6

TOP(S)=p9

pi=p10

∠p6p9p10は右回り

p9をPOP

p0

stack S

p1

p3

p5

p6

凸包を計算するアルゴリズム Graham スキャン (Graham’s scan)

動作例

p0

p9

p2

p11

p12 p8

p7

p6

p5

p4

p10

p1

p3

i=10

NEXT-TO-TOP(S)=p5

TOP(S)=p6

pi=p10

∠p5p6p10は右回り

p6をPOP

p0

stack S

p1

p3

p5

p6

凸包を計算するアルゴリズム Graham スキャン (Graham’s scan)

動作例

p0

p9

p2

p11

p12 p8

p7

p6

p5

p4

p10

p1

p3

i=10

NEXT-TO-TOP(S)=p5

TOP(S)=p6

pi=p10

∠p5p6p10は右回り

p6をPOP

p0

stack S

p1

p3

p5

凸包を計算するアルゴリズム Graham スキャン (Graham’s scan)

動作例

p0

p9

p2

p11

p12 p8

p7

p6 p5

p4

p10

p1

p3

i=10

NEXT-TO-TOP(S)=p3

TOP(S)=p5

pi=p10

∠p3p5p10は右回り

p5をPOP

p0

stack S

p1

p3

p5

凸包を計算するアルゴリズム Graham スキャン (Graham’s scan)

動作例

p0

p9

p2

p11

p12 p8

p7

p6 p5

p4

p10

p1

p3

i=10

NEXT-TO-TOP(S)=p3

TOP(S)=p5

pi=p10

∠p3p5p10は右回り

p5をPOP

p0

stack S

p1

p3

凸包を計算するアルゴリズム Graham スキャン (Graham’s scan)

動作例

p0

p9

p2

p11

p12 p8

p7

p6 p5

p4

p10

p1

p3

i=10

NEXT-TO-TOP(S)=p1

TOP(S)=p3

pi=p10

∠p1p3p10は左回り

p10をPUSH

p0

stack S

p1

p3

凸包を計算するアルゴリズム Graham スキャン (Graham’s scan)

動作例

p0

p9

p2

p11

p12 p8

p7

p6 p5

p4

p10

p1

p3

i=10

NEXT-TO-TOP(S)=p1

TOP(S)=p3

pi=p10

∠p1p3p10は左回り

p10をPUSH

p0

stack S

p1

p3

p10

凸包を計算するアルゴリズム Graham スキャン (Graham’s scan)

動作例

p0

p9

p2

p11

p12 p8

p7

p6 p5

p4

p10

p1

p3

i=11

NEXT-TO-TOP(S)=p3

TOP(S)=p10

pi=p11

∠p3p10p11は左回り

p11をPUSH

p0

stack S

p1

p3

p10

凸包を計算するアルゴリズム Graham スキャン (Graham’s scan)

動作例

p0

p9

p2

p11

p12 p8

p7

p6 p5

p4

p10

p1

p3

i=11

NEXT-TO-TOP(S)=p3

TOP(S)=p10

pi=p11

∠p3p10p11は左回り

p11をPUSH

p0

stack S

p1

p3

p10

p11

凸包を計算するアルゴリズム Graham スキャン (Graham’s scan)

動作例

p0

p9

p2

p11

p12 p8

p7

p6 p5

p4

p10

p1

p3

i=12

NEXT-TO-TOP(S)=p10

TOP(S)=p11

pi=p12

∠p3p10p11は右回り

p11をPOP

p0

stack S

p1

p3

p10

p11

凸包を計算するアルゴリズム Graham スキャン (Graham’s scan)

動作例

p0

p9

p2

p11

p12 p8

p7

p6 p5

p4

p10

p1

p3

i=12

NEXT-TO-TOP(S)=p10

TOP(S)=p11

pi=p12

∠p3p10p11は右回り

p11をPOP

p0

stack S

p1

p3

p10

凸包を計算するアルゴリズム Graham スキャン (Graham’s scan)

動作例

p0

p9

p2

p11

p12 p8

p7

p6 p5

p4

p10

p1

p3

i=12

NEXT-TO-TOP(S)=p3

TOP(S)=p10

pi=p12

∠p3p10p11は左回り

p12をPUSH

p0

stack S

p1

p3

p10

凸包を計算するアルゴリズム Graham スキャン (Graham’s scan)

動作例

p0

p9

p2

p11

p12 p8

p7

p6 p5

p4

p10

p1

p3

i=12

NEXT-TO-TOP(S)=p3

TOP(S)=p10

pi=p12

∠p3p10p11は左回り

p12をPUSH

p0

stack S

p1

p3

p10

p12

凸包を計算するアルゴリズム Graham スキャン (Graham’s scan)

動作例

p0

p9

p2

p11

p12 p8

p7

p6 p5

p4

p10

p1

p3

以上で凸包が計算された

スタックSは確かに,

凸包の頂点を反時計回りの順に含んでいる

p0

stack S

p1

p3

p10

p12

凸包を計算するアルゴリズム Graham スキャン (Graham’s scan)

補足説明Ⅰ

偏角の大小比較

p0

p1

p2 p2のp0に関する偏角が,p1のp0に関する偏角より大きい

→p1がp2に対して時計回りの方向にある

→p1×p2が正

このように大小比較してソートすれば良い

凸包を計算するアルゴリズム Graham スキャン (Graham’s scan)

補足説明Ⅱ

右折,左折の判定

p0

p1

p2’ p2

右折 左折

∠p0p1p2がどちら回りなのか?

→p0p2がp0p1に関して時計回りか反時計回りかを判定すれば良い (33.1節 p936 参照)

p0p2がp0p1に対して 時計回りの時 → 右折

反時計回りの時 → 左折

凸包を計算するアルゴリズム Graham スキャン (Graham’s scan)

補足説明Ⅱ

右折,左折の判定

p0

p1

p2’

右折 例:右折の時

(p2-p0)×(p1-p0)>0

→p1p0に対してp0p2は時計回り

→ ∠p0p1p2は右折

凸包を計算するアルゴリズム Graham スキャン (Graham’s scan)

定理33.1 Graham スキャンの正当性

|Q|≧3 である点集合Qについて GRAHAM-SCAN を実行し,終了したとき,

スタックSはボトムからトップまで確かに CH(Q) の頂点を反時計回りに含んでいる.

Proof (以下、ホワイトボードを交えながら説明する) 2行目より後,点列<p1,p2,…,pm>を得る.

i=2,3,…,mに対して,部分集合 Qi={p0,p1,…pi} を定義する.

Q-Qm に含まれる点は,p0 に関する偏角が同じであるため取り除かれた点であり,

それらの点は CH(Q) に入らず,CH(Qm)=CH(Q) である.

よって,これは GRAHAM-SCAN が終了するとき,スタックSがボトムからトップまで反時計回りの順に CH(Qm) の頂点が積み重なるように構成されている,ということを示すのに十分である.

p0,p1,pm が CH(Q) の頂点であると同時に,p0,p1,pi は全て CH(Qi) の頂点であるということに注意しよう.

凸包を計算するアルゴリズム Graham スキャン (Graham’s scan)

この証明には以下に示す、ループの不変の性質を用いる:

6-9行目のループの繰り返しの毎回のスタートにおいて,スタック S は確かにボトムからトップまで CH(Qi-1) の頂点を反時計回りの順に含むように構成されている.(以下で証明) Initialization 最初に6行目を実行するとき,スタックSは確かに Q2=Qi-1 の頂点から構成され、3点からなるこの集合は自身の凸包を形成するので,この不変の性質は成り立つ。 さらに,頂点はボトムからトップまで反時計回りに現れる. Maintenance for ループの繰り返しに入ったとき,スタック S のトップは点 pi-1 であり,この点はこれ以前の繰り返しの終わり(もしくは最初の繰り返しの前,i=3のとき)にPUSHされたものである.

7-8行目の while ループが実行されたあとの,ただし9行目の pi がプッシュされる前の S のトップの点を pj とし,pk が S 上において pj の下にある点であるとする.

この瞬間においては pj が S のトップの点であり,まだ pi を S にプッシュしておらず,S は確かに for ループの j の時の繰り返しの後に含んでいたのと同じ点を含んでいる.

凸包を計算するアルゴリズム Graham スキャン (Graham’s scan)

ループの繰り返しによって,S は確かに CH(Qj) の頂点を含んでおり,それらはボトムからトップに反時計回りの順に現れる.

piがプッシュされる直前に注目することを続けよう.

図33.8(a)で触れているように,pi の p0 に関する偏角は pj のそれよりも大きいため,

∠pkpjpi は左回り(そうでなければ pj をPOPしなければならなかっただろう)であり,

S が確かに CH(Qj) の頂点を含んでいるので,

一度 pi をプッシュすると,スタックSは確かにCH(Qj∪{pi})の頂点を,今まで通りボトムからトップまで反時計回りの順に含むようになる.

p0

pj

pi

pk

p2

p1 図33.8(a)

(a)

piのp0に関する偏角はpjのそれよりも大きく,

角pkpjpiは左回りであるために,

piをCH(Q)に加えることで,

確かにCH(Qj∪{pi})の頂点を得る.

凸包を計算するアルゴリズム Graham スキャン (Graham’s scan)

さて,CH(Qj∪{pi}) が CH(Qi) と同じ点集合であることを示そう.

ある点 pt を for ループの i 番目の繰り返しの間にPOPされた点であり,

pr は pt がPOPされたときスタックSにおいて pt のすぐ下にある点と考える(pr は pj かもしれない).

∠prptpi は左回りではなく,pt の p0 に関する偏角は pr のそれよりも大きい.

図33.8(b)にあるように,ptはp0,pr,piが形成する三角形の内部に,

もしくは三角形の横になくてはならない(しかしそれは三角形の頂点ではない).

p0

pj

pr

pk

p2

p1 図33.8(b)

pi

pt (b)

もし角prptpiは左回りでないなら,

pt はp0,pr,pi によって形成される三角形の内部,

または横に存在することになり,CH(Qi) の頂点にはならない.

凸包を計算するアルゴリズム Graham スキャン (Graham’s scan)

pt は Qi の他の3点によって形成される三角形の内部に存在するので,

CH(Qi) の頂点とはなり得ないのは明らかである.

よって pt は CH(Qi) の頂点ではないので,

CH(Qi-{pt})=CH(Qi)

を得る.

p0

pj

pr

pk

p2

p1 図33.8(b)

pi

pt (b)

もし角prptpiは左回りでないなら,

pt はp0,pr,pi によって形成される三角形の内部,

または横に存在することになり,CH(Qi) の頂点にはならない.

凸包を計算するアルゴリズム Graham スキャン (Graham’s scan)

Pi を for ループにおける i 番目の繰り返しの間にPOPされた点の集合とする.

Pi の全ての点に equality(33.1節)が適用できるので,

繰り返しそれを適用することで CH(Qi-Pi)=CH(Qi) を示すことができる.

ただし Qi-Pi=Qj∪{pi} であり,

それゆえ CH(QjU{Pi})=CH(Qi-Pi)=CH(Qi)=CH(Qi) と結論付けることができる.

ひとたび pi がPUSHされると,スタックSは確かにボトムからトップまで CH(Qi) の頂点を反時計回りの順に含むようになるということを示した.

i をインクリメントすることによって次の繰り返しを維持するためのループの不変の性質が発生する.

Termination ループが終了するとき,i=m+1 となり,

したがってループの不変の性質はスタックSが確かにCH(Qm)の,

つまりCH(Q)の頂点が反時計回りの順に格納されていることを意味する.

これで証明は完了である.

凸包を計算するアルゴリズム Graham スキャン (Graham’s scan)

計算量の吟味

n=|Q| として,グラハムスキャンが O(nlogn)時間で終了するということを示す.

GRAHAM-SCAN(Q)

1 let 𝑝0 be the point in Q with the minimum y-coordinate,

or the leftmost such point in case of a tie

2 let <𝑝1, 𝑝2, … , 𝑝𝑚> be the remaining points in Q,

sorted by polar angle in counterclockwise order around 𝑝0 (if more than one point has the same angle, remove all but

the one that is farthest from 𝑝0)

3 PUSH(𝑝0,S)

4 PUSH(𝑝1,S)

5 PUSH(𝑝2,S)

6 for i ← 3 to m

7 do while the angle formed by points NEXT-TO-TOP(S), TOP(S), and 𝑝𝑖 makes nonleft turn

8 do POP(S)

9 PUSH(𝑝𝑖, S)

10 return S

凸包を計算するアルゴリズム Graham スキャン (Graham’s scan)

計算量の吟味

n=|Q| として,グラハムスキャンが O(nlogn)時間で終了するということを示す.

GRAHAM-SCAN(Q)

1 let 𝑝0 be the point in Q with the minimum y-coordinate,

or the leftmost such point in case of a tie

2 let <𝑝1, 𝑝2, … , 𝑝𝑚> be the remaining points in Q,

sorted by polar angle in counterclockwise order around 𝑝0 (if more than one point has the same angle, remove all but

the one that is farthest from 𝑝0)

3 PUSH(𝑝0,S)

4 PUSH(𝑝1,S)

5 PUSH(𝑝2,S)

6 for i ← 3 to m

7 do while the angle formed by points NEXT-TO-TOP(S), TOP(S), and 𝑝𝑖 makes nonleft turn

8 do POP(S)

9 PUSH(𝑝𝑖, S)

10 return S

Line 1

Θ(n)時間かかる

凸包を計算するアルゴリズム Graham スキャン (Graham’s scan)

計算量の吟味

n=|Q| として,グラハムスキャンが O(nlogn)時間で終了するということを示す.

GRAHAM-SCAN(Q)

1 let 𝑝0 be the point in Q with the minimum y-coordinate,

or the leftmost such point in case of a tie

2 let <𝑝1, 𝑝2, … , 𝑝𝑚> be the remaining points in Q,

sorted by polar angle in counterclockwise order around 𝑝0 (if more than one point has the same angle, remove all but

the one that is farthest from 𝑝0)

3 PUSH(𝑝0,S)

4 PUSH(𝑝1,S)

5 PUSH(𝑝2,S)

6 for i ← 3 to m

7 do while the angle formed by points NEXT-TO-TOP(S), TOP(S), and 𝑝𝑖 makes nonleft turn

8 do POP(S)

9 PUSH(𝑝𝑖, S)

10 return S

Line 2

偏角のソートするのにマージソートもしくはヒープソートを用い,

角度比較に33.1節のcross-product-methodを用いるので,O(nlogn)時間かかる

(偏角が同じになる最遠点を除いてすべて取り除くのはトータルでO(n)時間)

Θ(n)

凸包を計算するアルゴリズム Graham スキャン (Graham’s scan)

計算量の吟味

n=|Q| として,グラハムスキャンが O(nlogn)時間で終了するということを示す.

GRAHAM-SCAN(Q)

1 let 𝑝0 be the point in Q with the minimum y-coordinate,

or the leftmost such point in case of a tie

2 let <𝑝1, 𝑝2, … , 𝑝𝑚> be the remaining points in Q,

sorted by polar angle in counterclockwise order around 𝑝0 (if more than one point has the same angle, remove all but

the one that is farthest from 𝑝0)

3 PUSH(𝑝0,S)

4 PUSH(𝑝1,S)

5 PUSH(𝑝2,S)

6 for i ← 3 to m

7 do while the angle formed by points NEXT-TO-TOP(S), TOP(S), and 𝑝𝑖 makes nonleft turn

8 do POP(S)

9 PUSH(𝑝𝑖, S)

10 return S

Line 3-5

O(1)時間かかる Θ(n)

O(nlogn)

凸包を計算するアルゴリズム Graham スキャン (Graham’s scan)

計算量の吟味

n=|Q| として,グラハムスキャンが O(nlogn)時間で終了するということを示す.

GRAHAM-SCAN(Q)

1 let 𝑝0 be the point in Q with the minimum y-coordinate,

or the leftmost such point in case of a tie

2 let <𝑝1, 𝑝2, … , 𝑝𝑚> be the remaining points in Q,

sorted by polar angle in counterclockwise order around 𝑝0 (if more than one point has the same angle, remove all but

the one that is farthest from 𝑝0)

3 PUSH(𝑝0,S)

4 PUSH(𝑝1,S)

5 PUSH(𝑝2,S)

6 for i ← 3 to m

7 do while the angle formed by points NEXT-TO-TOP(S), TOP(S), and 𝑝𝑖 makes nonleft turn

8 do POP(S)

9 PUSH(𝑝𝑖, S)

10 return S

Θ(n)

O(nlogn)

O(1)

Line 6-9

m≦n-1なので,for ループの実行回数は高々n-3回

PUSHにはO(1)時間かかるから,各繰り返しは7-8行目の whileループを除けばO(1)時間かかる

よって while ループを除けば,for ループ全体はO(n)時間かかる

凸包を計算するアルゴリズム Graham スキャン (Graham’s scan)

計算量の吟味

n=|Q| として,グラハムスキャンが O(nlogn)時間で終了するということを示す.

GRAHAM-SCAN(Q)

1 let 𝑝0 be the point in Q with the minimum y-coordinate,

or the leftmost such point in case of a tie

2 let <𝑝1, 𝑝2, … , 𝑝𝑚> be the remaining points in Q,

sorted by polar angle in counterclockwise order around 𝑝0 (if more than one point has the same angle, remove all but

the one that is farthest from 𝑝0)

3 PUSH(𝑝0,S)

4 PUSH(𝑝1,S)

5 PUSH(𝑝2,S)

6 for i ← 3 to m

7 do while the angle formed by points NEXT-TO-TOP(S), TOP(S), and 𝑝𝑖 makes nonleft turn

8 do POP(S)

9 PUSH(𝑝𝑖, S)

10 return S

Θ(n)

O(nlogn)

O(1)

O(n) (ただし while ループは除く)

では,While ループの計算量はどうなるのか?

凸包を計算するアルゴリズム Graham スキャン (Graham’s scan)

計算量の吟味

結論から言えば,whileループにかかる時間はO(n)となる

これを示すのに,集計法(aggregation method)を用いる

i=0,1,…,m に対するそれぞれの点pi はスタックに一度しか積まれない

各PUSH命令に対し,POP命令は高々1回しか実行されない

少なくとも3点―p0,p1,pm―はスタックから決してPOPされることはない

→実際は高々 m-2回 のPOP命令が全体で実行される

While ループの各繰り返しはPOP命令を1回実行

→全体で高々m-2回の while ループの繰り返しが存在

7 do while the angle formed by points NEXT-TO-TOP(S), TOP(S), and 𝑝𝑖 makes nonleft turn

8 do POP(S)

Line 7-8

7行目の検査がO(1)時間かかるので,POPの各呼び出しにはO(1)時間かかる

m≦n-1 ⇒ m-2≦n-3

より,while ループにかかる時間はアルゴリズム全体でO(n)

凸包を計算するアルゴリズム Graham スキャン (Graham’s scan)

計算量の吟味

n=|Q| として,グラハムスキャンが O(nlogn)時間で終了するということを示す.

GRAHAM-SCAN(Q)

1 let 𝑝0 be the point in Q with the minimum y-coordinate,

or the leftmost such point in case of a tie

2 let <𝑝1, 𝑝2, … , 𝑝𝑚> be the remaining points in Q,

sorted by polar angle in counterclockwise order around 𝑝0 (if more than one point has the same angle, remove all but

the one that is farthest from 𝑝0)

3 PUSH(𝑝0,S)

4 PUSH(𝑝1,S)

5 PUSH(𝑝2,S)

6 for i ← 3 to m

7 do while the angle formed by points NEXT-TO-TOP(S), TOP(S), and 𝑝𝑖 makes nonleft turn

8 do POP(S)

9 PUSH(𝑝𝑖, S)

10 return S

Θ(n)

O(nlogn)

O(1)

O(n) (ただし while ループは除く) O(n) (全体で)

凸包を計算するアルゴリズム Graham スキャン (Graham’s scan)

計算量の吟味

n=|Q| として,グラハムスキャンが O(nlogn)時間で終了するということを示す.

GRAHAM-SCAN(Q)

1 let 𝑝0 be the point in Q with the minimum y-coordinate,

or the leftmost such point in case of a tie

2 let <𝑝1, 𝑝2, … , 𝑝𝑚> be the remaining points in Q,

sorted by polar angle in counterclockwise order around 𝑝0 (if more than one point has the same angle, remove all but

the one that is farthest from 𝑝0)

3 PUSH(𝑝0,S)

4 PUSH(𝑝1,S)

5 PUSH(𝑝2,S)

6 for i ← 3 to m

7 do while the angle formed by points NEXT-TO-TOP(S), TOP(S), and 𝑝𝑖 makes nonleft turn

8 do POP(S)

9 PUSH(𝑝𝑖, S)

10 return S

Θ(n)

O(nlogn)

O(1)

O(n) (6-9行目全体で)

凸包を計算するアルゴリズム Graham スキャン (Graham’s scan)

計算量の吟味

n=|Q| として,グラハムスキャンが O(nlogn)時間で終了するということを示す.

GRAHAM-SCAN(Q)

1 let 𝑝0 be the point in Q with the minimum y-coordinate,

or the leftmost such point in case of a tie

2 let <𝑝1, 𝑝2, … , 𝑝𝑚> be the remaining points in Q,

sorted by polar angle in counterclockwise order around 𝑝0 (if more than one point has the same angle, remove all but

the one that is farthest from 𝑝0)

3 PUSH(𝑝0,S)

4 PUSH(𝑝1,S)

5 PUSH(𝑝2,S)

6 for i ← 3 to m

7 do while the angle formed by points NEXT-TO-TOP(S), TOP(S), and 𝑝𝑖 makes nonleft turn

8 do POP(S)

9 PUSH(𝑝𝑖, S)

10 return S

O(nlogn)

結局,GRAHAM-SCAN 全体の計算量はソートの実行時間に依存

→O(nlogn)

凸包を計算するアルゴリズム Graham スキャン (Graham’s scan)

候補点をスタックSで管理しながら凸包問題を解く

入力集合Qの各点はいったんスタックに入れられ,CH(Q)の頂点でない点は最終的にはスタックから取り除かれる

アルゴリズム終了の時点で,スタックはCH(Q)の頂点だけを,境界面上での反時計回りの出現順に含む

p1

p0

入力集合 Q={p0,p1,p2,…,p12}

p2

p6

p5

p4

p3 p7

p0

stack

Graham’s scan 終了時のスタック

p1

p2

p6

p7

凸包を計算するアルゴリズム Jarvis の行進法 (Jarvis’s march)

パッケージ包装 (package wrapping) (またはギフト包装 (gift wrapping))という技法により凸包を計算

イメージ図:

物体X

包装紙

凸包を計算するアルゴリズム Jarvis の行進法 (Jarvis’s march)

パッケージ包装 (package wrapping) (またはギフト包装 (gift wrapping))という技法により凸包を計算

イメージ図:

包装紙

Jarvis の行進法 (Jarvis’s march)

パッケージ包装 (package wrapping) (またはギフト包装 (gift wrapping))という技法により凸包を計算

イメージ図:

凸包を計算するアルゴリズム

包装紙

Jarvis の行進法 (Jarvis’s march)

パッケージ包装 (package wrapping) (またはギフト包装 (gift wrapping))という技法により凸包を計算

イメージ図:

凸包を計算するアルゴリズム

包装紙

Jarvis の行進法 (Jarvis’s march)

パッケージ包装 (package wrapping) (またはギフト包装 (gift wrapping))という技法により凸包を計算

イメージ図:

h を CH(Q) の頂点数として,O(nh)時間で実行可能

→ h が o(logn) であるとき,Graham スキャンよりも漸近的に速い

凸包を計算するアルゴリズム

包装紙

Complete!!

Jarvis の行進法 (Jarvis’s march)

より形式的には

CH(Q)の頂点の系列 H={p0,p1,…ph-1} を求める.

点集合Qの中で最もy座標が小さい点を p0 とする.

p1 は p0に関して偏角最小の点,p2 は p1 に関して偏角最小の点,p3 は・・・としていく.

y座標が最大の点pk に到達したとき、凸包の右側チェインが完成.

左側チェインを構成するために,pkに関して負のx軸からの偏角が最小の点としてpk+1を選択.

これを p0 に戻ってくるまで続ける.

凸包を計算するアルゴリズム

右側チェイン 左側チェイン

H={p0,p1,…p4}

p0

p1

p2

p3

p4

凸包を計算するアルゴリズム Jarvis の行進法 (Jarvis’s march)

動作例

入力集合Q

凸包を計算するアルゴリズム Jarvis の行進法 (Jarvis’s march)

動作例

p0

集合Qに含まれる点のうち,

y座標の最も小さい点をp0とする

凸包を計算するアルゴリズム Jarvis の行進法 (Jarvis’s march)

動作例

p0

p0に関する各点の偏角を比較

凸包を計算するアルゴリズム

p0

p0に関する負の偏角が最小である点を次の頂点とする

Jarvis の行進法 (Jarvis’s march)

動作例

凸包を計算するアルゴリズム

p0

p1

p0に関する偏角が最小である点を次の頂点とする

Jarvis の行進法 (Jarvis’s march)

動作例

凸包を計算するアルゴリズム

p0

p1

p1に関する各点の偏角を比較

Jarvis の行進法 (Jarvis’s march)

動作例

凸包を計算するアルゴリズム

p0

p1

p1に関する偏角が最小である点を次の頂点とする

Jarvis の行進法 (Jarvis’s march)

動作例

凸包を計算するアルゴリズム

p0

p1

p2

p1に関する偏角が最小である点を次の頂点とする

Jarvis の行進法 (Jarvis’s march)

動作例

凸包を計算するアルゴリズム

p0

p1

p2

p2に関する各点の偏角を比較

Jarvis の行進法 (Jarvis’s march)

動作例

凸包を計算するアルゴリズム

p0

p1

p2

p2に関する偏角が最小である点を次の頂点とする

Jarvis の行進法 (Jarvis’s march)

動作例

凸包を計算するアルゴリズム

p0

p1

p2

p3

p2に関する偏角が最小である点を次の頂点とする

Jarvis の行進法 (Jarvis’s march)

動作例

凸包を計算するアルゴリズム

p0

p1

p2

y座標が最大の点p3に到達

右側チェインが完成

右側チェイン

p3

Jarvis の行進法 (Jarvis’s march)

動作例

凸包を計算するアルゴリズム

p0

p1

p2

右側チェイン

p3に関する各点の負の偏角を比較

p3

Jarvis の行進法 (Jarvis’s march)

動作例

凸包を計算するアルゴリズム

p0

p1

p2

右側チェイン

p3

p3に関する負の偏角が最小である点を次の頂点とする

Jarvis の行進法 (Jarvis’s march)

動作例

凸包を計算するアルゴリズム

p0

p1

p4

右側チェイン

p3

p2

p3に関する負の偏角が最小である点を次の頂点とする

Jarvis の行進法 (Jarvis’s march)

動作例

凸包を計算するアルゴリズム

p0

p1

p4

右側チェイン

p3

p2

p4に関する各点の負の偏角を比較

Jarvis の行進法 (Jarvis’s march)

動作例

凸包を計算するアルゴリズム

p0

p1

p4

右側チェイン

p4に関する負の偏角が最小である点を次の頂点とする

p3

p2

Jarvis の行進法 (Jarvis’s march)

動作例

凸包を計算するアルゴリズム

p0

p1

p4

右側チェイン

p4に関する負の偏角が最小である点を次の頂点とする

p3

p2

Jarvis の行進法 (Jarvis’s march)

動作例

凸包を計算するアルゴリズム

p0

p1

p4

右側チェイン

p3

p2

左側チェイン

p0に到達

左側チェインが完成

Jarvis の行進法 (Jarvis’s march)

動作例

Jarvis の行進法 (Jarvis’s march)

動作例

凸包を計算するアルゴリズム

p0

p1

p4

p3

p2

点集合Qの凸包が計算された

Jarvis の行進法 (Jarvis’s march)

Jarvisの行進法を左右のチェインを別々に構成するのではなく実行することも可能

→このような実行方法では,選ばれた最後の凸包の辺を覚えておき,凸包の辺の角度の列 が真に増加列であることが必要になる(0から2π の範囲で)

別々にチェインを構成する利点

→角度を明示的に計算する必要がない

計算量の吟味

偏角の比較は33.1節の技法を用いるとO(1)時間でできる

→ある参照点に関するn個の点の偏角の最小値はO(n)時間で計算可能

→アルゴリズム全体はO(nh)時間で計算可能

凸包を計算するアルゴリズム

CONTENTS

33.4 最近点対の発見

(Finding the pair of closest points)

最近点対とは?

最近点対を計算するアルゴリズム

CONTENTS

33.4 最近点対の発見

(Finding the pair of closest points)

最近点対とは?

最近点対を計算するアルゴリズム

最近点対(pair of closest points)とは?

n≧2点の集合Qの中の,2点間のユークリッド距離が最小である組

交通制御システムで,衝突を検出すること等に応用されている

p1(x1,y1) p2(x2,y2)

n点集合Q

p1,p2 のユークリッド距離: 𝑥1 − 𝑥22 + (𝑦1 − 𝑦2)

2

最近点対

CONTENTS

33.4 最近点対の発見

(Finding the pair of closest points)

最近点対とは?

最近点対を計算するアルゴリズム

凸包を計算するアルゴリズム

凸包を計算する様々なアルゴリズムの紹介

1. 腕力法 (brute-force method)

2. 分割統治法 (divided-and-conquer method)

腕力法(brute-force method)

力づくで強引な方法

→単に全ての 𝑛2

=Θ(𝑛2) 通りの点対を調べる

ある参照点と他の点全ての距離を計算し,最小値を保持しながら参照点を変えていく

→とてつもなく時間がかかる

最近点対を計算するアルゴリズム

参照点

最近点対を計算するアルゴリズム 分割統治法(divide-and-conquer algorithm)

アルゴリズム全体の計算量を T(n) とすると,T(n)=2T(n/2)+O(n)

→T(n)=O(nlogn) (口頭で説明)

点集合全体を分割し,2つの部分集合をつくる

それらの部分集合の最近点対を再帰的に計算

凸包を計算するアルゴリズム 分割統治法 (divide-and-conquer method)

n点の集合を,左から 𝑛/2 個の点からなる集合と右から 𝑛/2 個の点からなる集合の2つに分割し,これらの部分集合の最近点対を再帰的に計算する.

求める最近点対は,再帰呼び出しで見つかった点対

または,部分集合の一方に1点を,もう一方に1点を持つ点対である.

イメージ的には・・・ n点集合

左側の最近点対

右側の最近点対

2つの部分集合の片方ずつに

1つずつ要素を持つ最近点対

分割

凸包を計算するアルゴリズム 分割統治法 (divide-and-conquer method)

n点の集合を,左から 𝑛/2 個の点からなる集合と右から 𝑛/2 個の点からなる集合の2つに分割し,これらの部分集合の最近点対を再帰的に計算する.

求める最近点対は,再帰呼び出しで見つかった点対

または,部分集合の一方に1点を,もう一方に1点を持つ点対である.

イメージ的には・・・ n点集合

求めるべき最近点対

アルゴリズム全体の計算量を T(n) とすると,T(n)=2T(n/2)+O(n)

→T(n)=O(nlogn)

分割統治法 (divide-and-conquer method)

具体的には

毎回の再帰呼び出しで部分集合P⊆Q を入力とする

部分集合P の全ての点を含む配列 X と Y を用いる

→Xはx座標が昇順にソートされている

→Yはy座標の昇順にソートされている

再起呼び出しの段階でソートは行わない

→ソートを行うと実行時間の再起式は T(n)=2T(n/2)+O(logn)

→T(n)=O(𝑛𝑙𝑜𝑔2𝑛) となってしまう

→O(nlogn)とするためにはソーティングを実行せずに整列性を維持することが必要

→そこでプリソーティング(presorting)という考え方を用いる(後ほど説明)

凸包を計算するアルゴリズム

部分集合P |P|=5

X[0],Y[1]

X[1],Y[4]

X[2],Y[0]

X[4],Y[2]

X[0],Y[1]

分割統治法 (divide-and-conquer method)

アルゴリズムの動作(入力は P,X,Y)

|P|≦3のとき

→腕力法により |𝑃|2

個の点すべての点対を調べて最も近い点対を返す

|P|>3のとき

→再起呼び出しにより分割統治法を実行

凸包を計算するアルゴリズム

分割統治法 (divide-and-conquer method)

アルゴリズムの動作(入力は P,X,Y)

分割

凸包を計算するアルゴリズム

点集合P

X[2],Y[8]

X[0],Y[2]

X[1],Y[0]

X[3],Y[3]

X[4],Y[5]

X[6],Y[4]

X[5],Y[7]

X[7],Y[6]

X[8],Y[9]

X[9],Y[1]

分割統治法 (divide-and-conquer method)

アルゴリズムの動作(入力は P,X,Y)

分割

凸包を計算するアルゴリズム

点集合Pを2つの集合𝑃𝐿と𝑃𝑅に分割

X[2],Y[8]

X[0],Y[2]

X[1],Y[0]

X[3],Y[3]

X[4],Y[5]

X[6],Y[4]

X[5],Y[7]

X[8],Y[9]

X[9],Y[1]

集合𝑃𝐿 集合𝑃𝑅

X[7],Y[6]

分割統治法 (divide-and-conquer method)

アルゴリズムの動作(入力は P,X,Y)

分割

凸包を計算するアルゴリズム

点集合Pを2つの集合𝑃𝐿と𝑃𝑅に分割

𝑃𝐿の点は全て直線 l の左に

𝑃𝑅の点は全て直線 l の右に

くるような垂直線 l を求める

X[2],Y[8]

X[0],Y[2]

X[1],Y[0]

X[3],Y[3]

X[4],Y[5]

X[6],Y[4]

X[5],Y[7]

X[7],Y[6]

X[8],Y[9]

X[9],Y[1]

集合𝑃𝐿 集合𝑃𝑅

垂直線 l

分割統治法 (divide-and-conquer method)

アルゴリズムの動作(入力は P,X,Y)

分割

凸包を計算するアルゴリズム

配列Xを𝑋𝐿と𝑋𝑅に分割し,

それぞれ𝑃𝐿と𝑃𝑅の点をx座標の昇順に含むようにする

同様に配列Yを𝑌𝐿と𝑌𝑅に分割し,

それぞれ𝑃𝐿と𝑃𝑅の点をy座標の昇順に含むようにする

集合𝑃𝐿 集合𝑃𝑅

垂直線 l

𝑋𝐿[0],𝑌𝐿[1]

𝑋𝑅[0],𝑌𝑅[3]

𝑋𝐿[3],𝑌𝐿[2]

𝑋𝐿[1],𝑌𝐿[0]

𝑋𝐿[4],𝑌𝐿[3]

𝑋𝑅[3],𝑌𝑅[4]

𝑋𝑅[2],𝑌𝑅[2]

𝑋𝑅[1],𝑌𝑅[1]

𝑋𝑅[4],𝑌𝑅[0]

𝑋𝐿[2],𝑌𝐿[4]

分割統治法 (divide-and-conquer method)

アルゴリズムの動作(入力は P,X,Y)

統治

凸包を計算するアルゴリズム

Pを𝑃𝐿と𝑃𝑅に分割後,

再帰呼び出しを2回行う

(簡単のためこれ以上の分割を省略)

1回目(入力𝑃𝐿,𝑋𝐿,𝑌𝐿 )

では𝑃𝐿における最近点対を

2回目(入力𝑃𝑅,𝑋𝑅,𝑌𝑅 )

では𝑃𝑅における最近点対を

それぞれ求める

集合𝑃𝐿 集合𝑃𝑅

垂直線 l

𝑋𝐿[0],𝑌𝐿[1]

𝑋𝑅[0],𝑌𝑅[3]

𝑋𝐿[3],𝑌𝐿[2]

𝑋𝐿[1],𝑌𝐿[0]

𝑋𝐿[4],𝑌𝐿[3]

𝑋𝑅[3],𝑌𝑅[4]

𝑋𝑅[2],𝑌𝑅[2]

𝑋𝑅[1],𝑌𝑅[1]

𝑋𝑅[4],𝑌𝑅[0]

𝑋𝐿[2],𝑌𝐿[4]

𝑃𝐿の最近点対

𝑃𝑅の最近点対

分割統治法 (divide-and-conquer method)

アルゴリズムの動作(入力は P,X,Y)

統治

凸包を計算するアルゴリズム

𝑃𝐿と𝑃𝑅に対して求められた

最近点対の距離をそれぞれ𝛿𝐿 ,𝛿𝑅 とし,

集合𝑃𝐿 集合𝑃𝑅

垂直線 l

𝑋𝐿[0],𝑌𝐿[1]

𝑋𝑅[0],𝑌𝑅[3]

𝑋𝐿[3],𝑌𝐿[2]

𝑋𝐿[1],𝑌𝐿[0]

𝑋𝐿[4],𝑌𝐿[3]

𝑋𝑅[3],𝑌𝑅[4]

𝑋𝑅[2],𝑌𝑅[2]

𝑋𝑅[1],𝑌𝑅[1]

𝑋𝑅[4],𝑌𝑅[0]

𝑋𝐿[2],𝑌𝐿[4]

𝛿𝐿

𝛿𝑅

分割統治法 (divide-and-conquer method)

アルゴリズムの動作(入力は P,X,Y)

統治

凸包を計算するアルゴリズム

𝑃𝐿と𝑃𝑅に対して求められた

最近点対の距離をそれぞれ𝛿𝐿 ,𝛿𝑅 とし,

𝛿 =min(𝛿𝐿,𝛿𝑅) とする 集合𝑃𝐿 集合𝑃𝑅

垂直線 l

𝑋𝐿[0],𝑌𝐿[1]

𝑋𝑅[0],𝑌𝑅[3]

𝑋𝐿[3],𝑌𝐿[2]

𝑋𝐿[1],𝑌𝐿[0]

𝑋𝐿[4],𝑌𝐿[3]

𝑋𝑅[3],𝑌𝑅[4]

𝑋𝑅[2],𝑌𝑅[2]

𝑋𝑅[1],𝑌𝑅[1]

𝑋𝑅[4],𝑌𝑅[0]

𝑋𝐿[2],𝑌𝐿[4]

𝛿

分割統治法 (divide-and-conquer method)

アルゴリズムの動作(入力は P,X,Y)

統合

凸包を計算するアルゴリズム 最近点対は先ほど見つけた距離δの点対

もしくは,

1点を𝑃𝐿に,もう1点を𝑃𝑅にもつ距離𝛿′の点対

このアルゴリズムではそのような点があるかを判定する

(判定法については後ほど説明)

集合𝑃𝐿 集合𝑃𝑅

垂直線 l

𝑋𝐿[0],𝑌𝐿[1]

𝑋𝑅[0],𝑌𝑅[3]

𝑋𝐿[3],𝑌𝐿[2]

𝑋𝐿[1],𝑌𝐿[0]

𝑋𝐿[4],𝑌𝐿[3]

𝑋𝑅[3],𝑌𝑅[4]

𝑋𝑅[2],𝑌𝑅[2]

𝑋𝑅[1],𝑌𝑅[1]

𝑋𝑅[4],𝑌𝑅[0]

𝑋𝐿[2],𝑌𝐿[4]

𝛿

𝛿′

この場合は 𝛿′<δ となる距離𝛿′の点対が存在

したがって距離𝛿′の点対が返される

return

分割統治法 (divide-and-conquer method)

判定法

距離がδ 未満の点対が存在する場合,それらの2点は直線からδ 単位以内にあるはず

凸包を計算するアルゴリズム

l

𝑃𝑅 𝑃𝐿

𝑝𝐿 𝑝𝑅

図33.12(a)

図33.12(a)に示すように,それら2点は直線l を中心とする幅2δの垂直帯領域にあるはず

δ

分割統治法 (divide-and-conquer method)

そのような点対が存在すれば必ず見つけるために,以下のようなことを行う

凸包を計算するアルゴリズム

1. 配列Y から幅2δ の垂直帯領域にないすべての点を取り除いて,配列Y’を作る

配列Y’はYと同様にy座標に関してソートされている

𝑃𝐿 𝑃𝑅

垂直線 l

𝑋𝐿[0],𝑌𝐿[1]

𝑋𝑅[0],𝑌𝑅[3]

𝑋𝐿[3],𝑌𝐿[2]

𝑋𝐿[1],𝑌𝐿[0]

𝑋𝐿[4],𝑌𝐿[3]

𝑋𝑅[3],𝑌𝑅[4]

𝑋𝑅[2],𝑌𝑅[2]

𝑋𝑅[1],𝑌𝑅[1]

𝑋𝑅[4],𝑌𝑅[0]

𝑋𝐿[2],𝑌𝐿[4]

𝛿

分割統治法 (divide-and-conquer method)

そのような点対が存在すれば必ず見つけるために,以下のようなことを行う

凸包を計算するアルゴリズム

1. 配列Y から幅2δ の垂直帯領域にないすべての点を取り除いて,配列Y’を作る

配列Y’はYと同様にy座標に関してソートされている

𝑃𝐿 𝑃𝑅

垂直線 l

𝑋𝐿[0],𝑌𝐿[1]

𝑋𝑅[0],𝑌𝑅[3]

𝑋𝐿[3],𝑌𝐿[2]

𝑋𝐿[1],𝑌𝐿[0]

𝑋𝐿[4],𝑌𝐿[3]

𝑋𝑅[3],𝑌𝑅[4]

𝑋𝑅[2],𝑌𝑅[2]

𝑋𝑅[1],𝑌𝑅[1]

𝑋𝑅[4],𝑌𝑅[0]

𝑋𝐿[2],𝑌𝐿[4]

𝛿

分割統治法 (divide-and-conquer method)

そのような点対が存在すれば必ず見つけるために,以下のようなことを行う

凸包を計算するアルゴリズム

1. 配列Y から幅2δ の垂直帯領域にないすべての点を取り除いて,配列Y’を作る

配列Y’はYと同様にy座標に関してソートされている

𝑃𝐿 𝑃𝑅

垂直線 l

𝛿

後々の比較のために残しておく

Y’[0]

Y’[1]

Y’[2]

分割統治法 (divide-and-conquer method)

そのような点対が存在すれば必ず見つけるために,以下のようなことを行う

凸包を計算するアルゴリズム

𝑃𝐿 𝑃𝑅

垂直線 l

Y’[0]

Y’[1]

Y’[2]

2. 配列Y’ の各点pについて,pからδ単位内にあるY’ の点を求める 後々証明することだが,Y’ においてpに続く7点だけを考えれば良い pからこの7点までの距離を計算し,Y’ のすべての点対について それまでに見つかった最近点対の距離δ’ の履歴を管理しておく

𝛿 p=Y’[0] 最近点対の距離δ’=Y’[1] Y’[0]

分割統治法 (divide-and-conquer method)

そのような点対が存在すれば必ず見つけるために,以下のようなことを行う

凸包を計算するアルゴリズム

𝑃𝐿 𝑃𝑅

垂直線 l

Y’[0]

Y’[1]

Y’[2]

2. 配列Y’ の各点pについて,pからδ単位内にあるY’ の点を求める 後々証明することだが,Y’ においてpに続く7点だけを考えれば良い pからこの7点までの距離を計算し,Y’ のすべての点対について それまでに見つかった最近点対の距離δ’ の履歴を管理しておく

𝛿 p=Y’[0] 最近点対の距離δ’=Y’[1] Y’[0]

𝛿′

分割統治法 (divide-and-conquer method)

そのような点対が存在すれば必ず見つけるために,以下のようなことを行う

凸包を計算するアルゴリズム

𝑃𝐿 𝑃𝑅

垂直線 l

Y’[0] Y’[1]

Y’[2]

2. 配列Y’ の各点pについて,pからδ単位内にあるY’ の点を求める 後々証明することだが,Y’ においてpに続く7点だけを考えれば良い pからこの7点までの距離を計算し,Y’ のすべての点対について それまでに見つかった最近点対の距離δ’ の履歴を管理しておく

𝛿 p=Y’[0] 最近点対の距離δ’=Y’[1] Y’[0]

𝛿′

分割統治法 (divide-and-conquer method)

そのような点対が存在すれば必ず見つけるために,以下のようなことを行う

凸包を計算するアルゴリズム

𝑃𝐿 𝑃𝑅

垂直線 l

Y’[0]

Y’[1]

Y’[2]

2. 配列Y’ の各点pについて,pからδ単位内にあるY’ の点を求める 後々証明することだが,Y’ においてpに続く7点だけを考えれば良い pからこの7点までの距離を計算し,Y’ のすべての点対について それまでに見つかった最近点対の距離δ’ の履歴を管理しておく

𝛿 p=Y’[1] 最近点対の距離δ’=Y’[1] Y’[0]

𝛿′

分割統治法 (divide-and-conquer method)

そのような点対が存在すれば必ず見つけるために,以下のようなことを行う

凸包を計算するアルゴリズム

𝑃𝐿 𝑃𝑅

垂直線 l

Y’[0]

Y’[1]

Y’[2]

3. 𝛿′<δ の場合,この垂直帯領域は再帰呼び出しで見つけられたものより近 い点対を確かに含んでいる そこで,この点対とその距離𝛿′ を返す そうでなければ,再帰呼び出しで見つかった最近点対とその距離δ を返す

𝛿 左図より 𝛿′<δ したがって Y’[0],Y’[1]とその距離𝛿′ が返る

𝛿′ return

この説明ではO(nlogn)の実行時間を達成するために必要になる実行上の詳細な部分を省略している

アルゴリズムの正当性を説明したあとで,この目標の限界を達成するためのアルゴリズムの実行法を示す

分割統治法 (divide-and-conquer method)

正当性

アルゴリズムは次の2点を除いて明白

1. |P|≦3 のときのアルゴリズムの正当性

→これ以上再帰を行えないことによって,1点からなる部分問題を解かなくてもいいという

ことがわかる

2. 配列Y’において,各点に続く7点だけを調べれば良い

→以下でこれを証明していく

凸包を計算するアルゴリズム

分割統治法 (divide-and-conquer method)

正当性

再起のとあるレベルにおいて最近点対が 𝑝𝐿 ∈ 𝑃𝐿 と 𝑝𝑅 ∈ 𝑃𝑅であるとする

→ 𝑝𝐿と𝑝𝑅の距離は真にδより小さい

→ 𝑝𝐿は直線lまたはその左にあり,δ単位以上離れていない

→ 𝑝𝑅は直線lまたはその右にあり,δ単位以上離れていない

→ 𝑝𝐿と𝑝𝑅は互いに垂直方向にδ単位以内にある

→ 𝑝𝐿と𝑝𝑅は直線lを中心とするδ × 2𝛿の長方形の中にある

凸包を計算するアルゴリズム

l

𝑃𝑅 𝑃𝐿

𝑝𝐿 𝑝𝑅

図33.12(a)

δ

分割統治法 (divide-and-conquer method)

正当性

δ × 2𝛿の長方形の中にPの点が高々8個しかないことを示す

この長方形のδ × 𝛿の正方形を考える

→ 𝑃𝐿内の点はすべて少なくとも𝛿だけ離れている

→ 正方形の中には高々4点しか存在しない(𝑃𝑅も同様)

→ 長方形内にはPの点が高々8点しか存在し得ない

配列Y’の各点に続く7点だけを調べれば良いことを示す

配列Y’において𝑝𝐿は𝑝𝑅よりも前にあると仮定する

→ 一般性は失われない

→ 𝑝𝐿が配列Y’においてどんな前にあり,𝑝𝑅がどんな後に

あろうとも𝑝𝑅は𝑝𝐿に続く7個の位置のどれかにある

凸包を計算するアルゴリズム

δ

δ δ

𝑃𝑅 𝑃𝐿

重複点:一方が𝑃𝐿上にあり、

もう一方が𝑃𝑅上にある 重複点:一方が𝑃𝐿上にあり、

もう一方が𝑃𝑅上にある

図33.12(b) 以上で,最近点対アルゴリズムの正当性が示された

分割統治法 (divide-and-conquer method)

実現性と実行時間

主な難しさは以下の2点である

1. 再帰呼び出しで渡される配列𝑋𝐿 , 𝑋𝑅 , 𝑌𝐿, 𝑌𝑅が座標の順にソートされていること

2. Y’がy座標でソートされていること

もし以上の2つが保証されるのなら,集合Pを𝑃𝐿と𝑃𝑅に分割するのは線形時間で出来る

→各呼び出しにおいてソート済みの配列からソートされた部分集合をどうやって形成するかが鍵

(例: Pを𝑃𝐿と𝑃𝑅に分割した後,y座標でソートされた配列𝑌𝐿と𝑌𝑅を線形時間で作らなければならない)

→1.3.1節で述べたマージソートの手続きMERGEとは逆の方法を取ることで条件を満たすようにする

凸包を計算するアルゴリズム

分割統治法 (divide-and-conquer method)

実現性と実行時間

その考えを説明したのが以下の擬似コードである

凸包を計算するアルゴリズム

1 length[𝑌𝐿] ← length[𝑌𝑅] ← 0

2 for i ← 1 to length[Y]

3 do if Y[i] ∈ 𝑃𝐿

4 then length[𝑌𝐿] ← length[𝑌𝐿] + 1

5 Y[length[𝑌𝐿]] ← Y[i]

6 else length[𝑌𝑅] ← length[𝑌𝑅] + 1

7 Y[length[𝑌𝑅]] ← Y[i]

分割統治法 (divide-and-conquer method)

実現性と実行時間

その考えを説明したのが以下の擬似コードである

凸包を計算するアルゴリズム

1 length[𝑌𝐿] ← length[𝑌𝑅] ← 0

2 for i ← 1 to length[Y]

3 do if Y[i] ∈ 𝑃𝐿

4 then length[𝑌𝐿] ← length[𝑌𝐿] + 1

5 Y[length[𝑌𝐿]] ← Y[i]

6 else length[𝑌𝑅] ← length[𝑌𝑅] + 1

7 Y[length[𝑌𝑅]] ← Y[i]

Line 2-7 for ループ

配列Yの点を順に調べていく

分割統治法 (divide-and-conquer method)

実現性と実行時間

その考えを説明したのが以下の擬似コードである

凸包を計算するアルゴリズム

1 length[𝑌𝐿] ← length[𝑌𝑅] ← 0

2 for i ← 1 to length[Y]

3 do if Y[i] ∈ 𝑃𝐿

4 then length[𝑌𝐿] ← length[𝑌𝐿] + 1

5 Y[length[𝑌𝐿]] ← Y[i]

6 else length[𝑌𝑅] ← length[𝑌𝑅] + 1

7 Y[length[𝑌𝑅]] ← Y[i]

Line 3-5

点Y[i]が𝑃𝐿にあればそれを𝑌𝑅の最後に追加する

分割統治法 (divide-and-conquer method)

実現性と実行時間

その考えを説明したのが以下の擬似コードである

凸包を計算するアルゴリズム

1 length[𝑌𝐿] ← length[𝑌𝑅] ← 0

2 for i ← 1 to length[Y]

3 do if Y[i] ∈ 𝑃𝐿

4 then length[𝑌𝐿] ← length[𝑌𝐿] + 1

5 Y[length[𝑌𝐿]] ← Y[i]

6 else length[𝑌𝑅] ← length[𝑌𝑅] + 1

7 Y[length[𝑌𝑅]] ← Y[i]

Line 6-7

そうでなければそれを𝑌𝑅の最後に追加する

分割統治法 (divide-and-conquer method) プリソーティング (presorting) と計算量

点集合Qの点を一度だけ,最初の再帰呼び出しの前にソートしておくだけで良い

プリソーティングのために余分にO(nlogn)の時間がかかるが,

再帰の各ステップでは再帰呼び出し以外では線形時間しかかからない

→T(n)を各再帰ステップの実行時間とし,T’(n)を全体の実行時間とすると,

T’(n)=T(n)+O(nlogn)

及び,

T(n)= 2𝑇

𝑛

2+ 𝑂 𝑛 𝑛 > 3

𝑂 1 𝑛 ≥ 3

を得る

したがって,T(n)=O(nlogn)より T’(n)=O(nlogn) を得る

凸包を計算するアルゴリズム