1 / 51

アルゴリズム概論 講義資料

アルゴリズム概論 講義資料.  関先生の講義資料を利用させていただきました。 資料の利用を快諾していただいた関先生に感謝   します。  参考書     石畑 清著:      「アルゴリズムとデータ構造」 (岩波書店). グラフのアルゴリズム. 探索 5/12 連結性 5/14 最短経路 5/19. 有向グラフ (directed graph). 頂点(節点) (vertex, node). 道 (path) :辺で結ばれた頂点の列. v1,v2,v3,v4,v2 (長さ4)など.

Télécharger la présentation

アルゴリズム概論 講義資料

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. アルゴリズム概論 講義資料 •  関先生の講義資料を利用させていただきました。 資料の利用を快諾していただいた関先生に感謝   します。 •  参考書     石畑 清著:      「アルゴリズムとデータ構造」 (岩波書店)

  2. グラフのアルゴリズム • 探索 5/12 • 連結性 5/14 • 最短経路 5/19

  3. 有向グラフ (directed graph) 頂点(節点) (vertex, node) • 道 (path) :辺で結ばれた頂点の列.v1,v2,v3,v4,v2(長さ4)など. • 閉路 (cycle):先頭と末尾の頂点が等しい道.v2,v3,v4,v2など. v1 v2 v5 v3 辺(枝) (edge, arc) v4

  4. 無向グラフ (undirected graph) • 道 v1,v2,v3,v4,v2 や v2,v3,v1,v3 • 閉路 v1,v2,v3,v1 など v1 v2 v5 v3 v4

  5. 重みつきグラフ 2 3 4 8 1 3 2 5 • 辺に数値(重み)をつけることがある(有向グラフでも). • (重みの例)頂点 辺 重み  駅 路線 距離または運賃 計算機 回線 コスト v1 v2 v5 v3 v4

  6. 仮定 有向グラフ 無向グラフ • 多重辺 • 自己閉路 はないと仮定.

  7. グラフのサイズ(大きさ)の尺度 • 頂点数n, 辺の数m nとmの関係は? 完全グラフ(すべての頂点間に辺が存在するグラフ)のとき    無向グラフ             有向グラフ m=n(n-1)/2 m=n(n-1)

  8. グラフのサイズ(つづき)   無向グラフ         有向グラフ 0≦m≦n(n-1)/2 0≦m≦n(n-1) O(n2) O(n2) m∈ O(n2) : 密なグラフ m∈ O(n) : 疎なグラフ 計算量   m∈ O(n2) m∈ O(n) O(m+n) O(n2) O(n) O(n log n) O(n log n) O(n log n) (どちらが効率が良いかはグラフの疎/密に依存)  

  9. グラフの表現法 0 1 (*を0にするか 1にするかは任意) 必要な領域 O(n2) O(m+n) 0 1 2 3 0 * 1 1 0 1 0 * 0 1 2 0 1 * 1 3 0 0 0 * 2 3 隣接行列 隣接リスト

  10. 深さ優先探索 (depth first search) • 訪問順:1 • 2 • 3 • 5 • 6 • 7 • グラフの探索:すべての頂点をちょうど1回ずつ訪問する方法. A C A E B C 木の辺 D G F E 逆辺 F D G B

  11. 寄り道(C言語のデータ型) int x ; (宣言: xはint(整数)型の変数) struct { int height ; int weight ; } y ; (yはheight, weightという二つのメンバーをもつ構造体の変数) y.height = 169 ; y.weight = 58 ; z = y.height – 110 ; height: weight:

  12. C言語(構造体,ポインタ) struct hwdata { int height ; int weight ; } ; struct hwdata y ; でも同じ (hwdataと型名をつけた). int *p ; (pはint型の値を指すポインタ型変数) *p = 315 ; struct hwdata *p ; (*p).height=169 ;   (p->height=169 と略記) height: weight: hwdata型 p p

  13. C言語(リスト構造の表現) dest next struct cell { int dest ; %辺の行き先頂点 struct cell *next ; } ; struct cell *p ; p->dest = 15 ; p->next = NULL ; typedef struct cell *elist; と型定義しておくと, struct cell *p の代わりに, elist pと書ける. cell型 p NULL(=0, 何も 指していない)

  14. 隣接リスト(C言語の構造体配列) struct { int state ; elist adjlist ; } vertex[1000] ; (vertexはサイズ1000の 配列で,その要素は int型のstateと elist型のadjlistという 二つのメンバーをもつ 構造体) state adjlist 0 1 2 3 NULL visited(=1)または unvisited(=0). 配列vertex

  15. 深さ優先探索(抽象的アルゴリズム) { for (i=0; i<n; i++) %nは頂点数 vertex[i].state=unvisited ; %初期化 for (i=0; i<n; i++) %各頂点iから探索開始 if (vertex[i].state==unvisited) dfs(i) ; % 頂点をまだ訪問していなければdfs(i)を行う. } dfs(v) { vertex[v].state=visited ; 頂点vに対する処理 ; for (vを始点とする各辺について) { d=辺の行き先の頂点 ; 辺(v, d)に対する処理 ; if(vertex[d].state==unvisited)dfs(d); } }

  16. 深さ優先探索(詳細化) dfs(v) { int d; elist p; vertex[v].state=visited ; 頂点vに対する処理 ; p=vertex[v].adjlist ; while (p!=NULL) { d=p->dest ; 辺(v, d)に対する処理 ; if(vertex[d].state==unvisited) dfs(d); p=p->next ; } }

  17. 深さ優先探索(有向グラフ) 訪問順:1 6 2 4 7 3 5 A F A F 上昇辺 B G G E C C D 交差辺 D 木の辺 下降辺 B E

  18. トポロジカルソート(有向グラフ) • 道v1→v2→...→vn(v1≠vn)があるとき,v1→+ vnと書く. • DAG (directed acyclic graph): 閉路をもたない有向グラフ. • トポロジカルソート問題:与えられたDAGの全頂点を,関係→+に矛盾しないように並べよ. u1 u2 u3 u4 ... un  と並べたとき, ui→+ uj ならば i<j でなければならない.(ujがuiより前に現れてはならない.) ×

  19. トポロジカルソート(つづき) v1 → v2 ← v5 v3 → v4 v1 → v5 → v2 → v3 → v4 v1 v2 v5 v3 v4 トポロジカルソート ではない. トポロジカルソート

  20. ④ ① ② トポロジカルソート(アルゴリズム) • 3 • 2 • 1 v1 v2 Step1 深さ優先探索をし, 帰りがけに番号をふる. Step2 その番号の大きい 順に頂点を並べる. v1 → v5 → v2 → v3 → v4 ji ... uv ... ( j>i) と並んだとき,v →+ uとはならない.なぜなら,もしv →+ uならばvからuへの道があるので,vに番号づけする前にuに番号づけするはずだから. v5 v3 v4 5 4 3 2 1

  21. 連結性 • 無向グラフが連結:任意の2頂点間に道があること.    連結         連結でない • 有向グラフが強連結:任意の2頂点 u, v について,uからvへの道があること. 強連結         強連結でない

  22. 2重連結性 (biconnected) • 無向グラフが2重連結:どの1頂点を取り除いても,残ったグラフが連結であること. • 関節点:それを取り除くと連結でなくなるような頂点.(関節点をもたないグラフは2重連結.よって,関節点の検出法があれば2重連結かどうかも分かる.) • 2重連結成分:2重連結であるような極大な部分グラフ. 関節点

  23. 関節点の検出アルゴリズム • 根頂点Aが関節点である⇔ Aが子頂点を2つ以上もつ A A

  24. B D C B F G D E E G C H H F 関節点の検出(つづき) ↑1 ↑1  ↑ 3     ↑ 1         ↑ 1         ↑ 5         ↑ 5 1 2 3 4 5 6 7 • 根頂点以外の場合 • 深さ優先探索を行う. • 1, 2, ... : 行きがけに番号付け    •       (順序数) • ↑1, ↑3, ... : 木の辺を下向きに0回 • 以上たどった後,逆辺を0または1回 • たどって至る頂点の順序数の最小値

  25. 関節点の検出(正当性) 根頂点でないAが関節点である⇔   深さ優先探索木中,Aの下の部分木で,Aの祖先への逆辺をもたないものが存在する. (証明)(⇒を証明する.逆も同様に証明できる.)対偶を背理法により証明する.Aのどの部分木からも,Aのある祖先への逆辺があるとし,Aが関節点であると仮定する.あるB, Cが存在して,BC間の道は全てAを通る.

  26. 関節点の検出(正当性つづき) • BがAの祖先,CがAの子孫のとき.  仮定より右のような逆辺がある.よってAは関節点でない.∴矛盾. B A C :道を表す

  27. 関節点の検出(正当性つづき) • B, CがAの子孫のとき.  仮定より右のような逆辺がある.よってAは関節点でない.∴矛盾. A B C

  28. 有向グラフの強連結成分 • 強連結であるような極大な部分グラフ. 縮約(簡約)グラフ

  29. 強連結成分を求めるアルゴリズム ↑1       ↑1    ↑7    ↑1   ↑3      ↑9 ↑1       ↑5           ↑5 • 深さ優先探索を行い,各頂点vに,順序数seq(v)と lowlink(v)をふる. lowlink(v) : 木の辺を下向きに0回以上たどった後,同じ強連結成分内の上昇辺または交差辺を0または1回たどって至る頂点の順序数の最小値. 1 2 8 3 7 9 4 5 6 ↑1: lowlink 3 :順序数

  30. アルゴリズムの正当性 頂点vが強連結成分の根⇔lowlink(v)=seq(v) (証明)(⇒)lowlink(v)≠seq(v)と仮定. lowlink(v)<seq(v)である.seq(w)=lowlink(v) とすると, どちらの場合も, vは強連結成分 の根ではない. W W V V

  31. アルゴリズムの正当性(つづき) (⇐)vが強連結成分の根ではないと仮定.vから強連結成分の根への道が存在する.その道上でvの子孫でない最初の頂点をwとすると, lowlink(v)≦seq(w)<seq(v). w v

  32. 強連結成分(アルゴリズムの概要) ↑1      ↑1 ↑7 ↑1 ↑3 ↑9 ↑1 ↑5 ↑5 1 12345678 1 2 8 12345678 3 7 9 123456789 1234 4 5 1234 123456 強連結成分 6 123456 lowlink(v)=seq(v)となったら スタックをvまでポップ

  33. 強連結成分(抽象的アルゴリズム) struct { int seq ; %序数を記憶 elist adjlist ; %隣接リスト } vertex[1000] ; %入力グラフ int count, sp, i, stack[1000] ; for (i=0; i<n; i++) vertex[i].seq=0; %初期化 count=0 ; sp=-1 ; for (i=0; i<n; i++) if (vertex[i].seq==0)%頂点iをまだ訪問していない scc(i) ;

  34. 強連結成分(アルゴリズム,つづき) scc(v) { % lowlink(v)を計算しながら, % 強連結成分が検出されたら出力 count++; vertex[v].seq=count; min=count; sp++; stack[sp]=v; for (vを始点とする各辺(v,d)について) { if (まだdを訪問していない) m=scc(d); else m=vertex[d].seq ; %(v,d)は上昇辺か交差辺 if (m<min) min=m ; if (min==vertex[v].seq) %vは強連結成分の根 スタックstackを先頭からvまでポップしながら出力; return(min) ; } }

  35. 最短経路 (shortest path) 1 2 5 3 6 vからwへの最短経路:vからwへの道で辺 の重み和が最小のもの(複数存在することも) v1からv3への道: v1 v2 v3 4 v1 v3 5 v1 v4 v3 8 v1からv3への最短経路:v1 v2 v3 v1 v2 v4 v3

  36. Dijkstraのアルゴリズム(概要) 出発点sからの最短経路が求まっている頂点集合をV, 求まっていない頂点集合をUとする. • V=空集合; U=全頂点集合; s.distance=0 ; s以外の頂点vについてv.distance=∞と初期化; • U=空集合となるまで以下を繰り返す; • Uからdistanceが最小の頂点pを選びVに移す; • Uに属する頂点xで辺p→xが存在するものについて,x.distance>p.distance+(p→xの重み)なら,x.distanceをp.distance+(p→xの重み)に変更する; 6 6 3 3 ∞ 5 5 8 2 2 V V U U 9 7

  37. Dijkstraのアルゴリズム(実行例) (辺の重みは,すべて正か0とする) U V 1 1 3 0 ∞ 3 0 1 5 5 2 3 2 3 5 3 ∞ ∞ 5 3 5 ∞ 2 2 3 ∞ ∞ 3 2 5 1 1 1 1 3 0 1 5 3 0 1 5 2 3 2 3 5 3 4 ∞ 5 3 4 ∞ 2 2 3 2 4 3 2 3 1 1

  38. Dijkstraのアルゴリズム(つづき) 1 1 3 0 1 5 3 0 1 5 2 3 2 3 5 3 4 6 2 5 3 4 6 2 3 2 3 3 1 2 3 1 1 3 0 1 5 2 3 5 3 4 6 2 3 2 3 1

  39. Dijkstraのアルゴリズム(正当性) V U (性質)V内の各頂点wには,V内の頂点のみを経由するsからwへの最短経路が求まっていると仮定する.アルゴリズムが頂点pを選んだとする.sからpへの最短経路で,V内の頂点だけを経由するものがある. p s(出発点)

  40. Dijkstra(正当性,つづき) V U p (証明)背理法.sからpへの最短経路はすべてU内の頂点を通るとする.最初に訪れるU内の頂点をqとする.上の図で,重み和について, sqp < sp qp ≧ 0 より, sq < sp これはアルゴリズムがpを選んだことに矛盾. (重み≧0の仮定が本質的.) s(出発点) q

  41. Dijkstraのアルゴリズム(データ構造) struct { int state ; int disance ; %始点からの重み和を記憶 elist adjlist ; } vertex[1000] ; %入力グラフ struct cell { int dest ; %辺の行き先の頂点 int weight ; %辺の重み struct cell *next } ;%隣接リストで使う辺を表す構造体

  42. Dijkstraのアルゴリズム(詳細化) dijkstra(s) { % sは出発点 for (i=0; i<n; i++) { vertex[i].state=unvisited ; vertex[i].distance=∞ ; } vertex[s].distance=0 ; % 出発点sからs自身への重み和は0

  43. Dijkstraのアルゴリズム(つづき) for (step=0; step<n; step++) { min=∞ ; for (i=0; i<n; i++) { if (vertex[i].state==unvisited && vertex[i].distance<min) { p=i; min=vertex[i].distance; } } if (min==∞) error ; vertex[p].state=visited ; for(e=vertex[p].adjlist;e!=NULL;e=e->next){ x=e->dest; vertex[x].distace =min(vertex[x].distance, vertex[p].distance+(e->weight)) ; } } }

  44. Dijkstraのアルゴリズム(計算量) • 最初のfor文 n回 • 2つめのfor文 n回 • 内側の2つのfor文 いずれもn回 • よって全体で,O(n2). • ヒープを使うとO((m+n)log n)にできる.疎なグラフだとこの方が早い. 補足:前ページで, min(x,y) { if (x>=y) return(x) ; else return(y) ; }

  45. Greedy(グリーディ)アルゴリズム • 局所的に(その都度)最適なものを選択するような戦略. • 全体として最適解が得られるとは限らない(例:荷物の箱づめ,ゲーム). • Dijkstraのアルゴリズムは,グリーディアルゴリズムで全体の最適解を求めることのできる典型例.

  46. Floydの方法 • 全頂点間の最短経路を求める. • ak[i,j] : 頂点0,1,...,kだけを通って,頂点iからjへ至る道の最短長. • 特に,a0[i,j]: 辺 i→j の重み.ただし,i=jのとき0, 辺i→jが存在しないとき∞. 考察 • an-1[i,j]は,iからjへの最短経路長(重み和)となる. • ak-1[*,*]からak[*,*]を求める方法が見つかれば,a0[*,*]から順に,an-1[*,*]を求めることができる.

  47. Floydのアルゴリズム(アイディア) ak-1[i,j] ak[i,j]=min(ak-1[i,k]+ak-1[k,j], ak-1[i,j]) i j どちらか短い方がak[i,j] つまり, ak-1[k,j] ak-1[i,k] k

  48. Floydのアルゴリズム(詳細化) { for (i=0; i<n; i++) for (j=0; j<n; j++) a[i,j]=辺i→jの重み; %i=jのとき0, 辺i→jがないとき∞ for (k=0; k<n; k++) for (i=0; i<n; i++) for (j=0; j<n; j++) a[i,j]=min(a[i,k]+a[k,j], a[i,j]); } 時間計算量 O(n3)

  49. Floydのアルゴリズム(メモリ管理) 前ページのアルゴリズム:一つの配列で,a0[*,*], a1[*,*], ... を重ね書きしている. → 重ね書きして大丈夫か?

  50. Floydのアルゴリズム(つづき) ak[i,k]=min(ak-1[i,k]+ak-1[k,k], ak-1[i,k]) =ak-1[i,k].同様に,ak[k,j]=ak-1[k,j]. よって,     の値を使ってもOK! ak[i,j]=min(ak-1[i,k]+ak-1[k,j], ak-1[i,j]) 0 1 2 3 4 0 1 2 3 4 5 1 6 7 8 9 10 2 11 12 13 14 15 3 16 . . . 4 :計算済      を求める のに, k=1のとき,   を使う.

More Related