最短経路.

Slides:



Advertisements
Similar presentations
山元進.  for 文  while 文  do ~ while 文  文のネスト  break 文  continue 文.
Advertisements

プログラミング実習 1 ・ 2 ク ラス 第 2 週目 担当教員 : 渡邊 直樹. 課題 2 ● 2 × 2型行列の固有値, 固有ベクトルを求め る EigMatrix.java というプログラムを作成せ よ。 ● 行列の各要素はコマンド・プロンプトから入力 ● 計算した結果もコマンド・プロンプトに表示.
6.4継承とメソッド 6.5継承とコンストラクタ 11月28日 時田 陽一
配列の宣言 配列要素の初期値 配列の上限 メモリ領域 多次元配列 配列の応用
プログラムのパタン演習 解説.
アルゴリズムとデータ構造 2012年6月27日
プログラミング入門2 第4回 配列 for文 変数宣言 初期化
プログラミング基礎I(再) 山元進.
第11回 整列 ~ シェルソート,クイックソート ~
第11回 整列 ~ バケットソート,基数ソート,ヒープソート~
アルゴリズムとプログラミング (Algorithms and Programming)
プログラミング基礎I(再) 山元進.
第2回:Javaの変数と型の宣言 プログラミングII 2007年10月2日.
情報工学概論 (アルゴリズムとデータ構造)
String - 文字列 2009年10月9日 7ADD2116 佐藤洋輔.
プログラミング実習 1・2 クラス 第 1 週目 担当教員:  渡邊 直樹.
繰り返し プログラミング 第4回 繰り返し プログラミング第4回.
第20章 Flyweight ~同じものを共有して無駄をなくす~
インタフェース プログラミング 第14回 インタフェース プログラミング第14回.
大岩 元 慶応大学環境情報学部 二分木 データ構造とプログラミング(10) 大岩 元 慶応大学環境情報学部
オブジェクト指向入門.
アルゴリズムとデータ構造 2011年6月20日
データ構造と アルゴリズム 第四回 知能情報学部 新田直也.
アルゴリズム入門.
第13回 ハッシュテーブルを使ったプログラム ~高速に検索するには?~.
~手続き指向からオブジェクト指向へ[Ⅱ]~
プログラミング言語入門 手続き型言語としてのJava
アルゴリズムとデータ構造 2011年7月4日
アルゴリズムとデータ構造 2012年6月28日
アルゴリズムとデータ構造 2011年6月27日
アルゴリズムとプログラミング (Algorithms and Programming)
第9章 例外処理,パッケージ 9.1 例外処理 9.2 ガーベッジコレクション.
オブジェクト指向 プログラミング 第十三回 知能情報学部 新田直也.
アルゴリズムとデータ構造 2013年7月16日
アルゴリズムとプログラミング (Algorithms and Programming)
プログラミング演習3 第2回 GUIの復習.
オブジェクト指向 プログラミング 第七回 知能情報学部 新田直也.
アルゴリズム入門.
アルゴリズムとデータ構造 2012年7月17日
データ構造と アルゴリズム 第五回 知能情報学部 新田直也.
アルゴリズムとデータ構造1 2005年6月24日
オブジェクト指向 プログラミング 第六回 知能情報学部 新田直也.
算法数理工学 第8回 定兼 邦彦.
計算機プログラミングI 第5回 配列 文字列(Stringクラス) mainの引数 配列の利用例
アルゴリズムとデータ構造 2011年6月23日
6.データ構造入門 6-1.連結リスト(Linked List) 6-2.スタック(Stack) 6-3.キュー(Queue)
情報知能学科「アルゴリズムとデータ構造」
アルゴリズムとプログラミング (Algorithms and Programming)
オブジェクト指向 プログラミング 第九回 知能情報学部 新田直也.
プログラミング言語論 第十三回 理工学部 情報システム工学科 新田直也.
オブジェクト指向 プログラミング 第六回 知能情報学部 新田直也.
計算機プログラミングI 木曜日 1時限・5時限 担当: 増原英彦 第1回 2002年10月10日(木)
アルゴリズムとデータ構造 2011年7月11日
JAVA入門③ 配列とコレクション.
アルゴリズムとプログラミング (Algorithms and Programming)
アルゴリズムとデータ構造 2011年6月28日
アルゴリズムとデータ構造 2013年7月1日
Chapter 5 5.5 thisキーワード 5.6 インスタンス変数とインスタンスメソッド 結城 隆
アルゴリズムとデータ構造 2013年7月8日
アルゴリズムとデータ構造 2012年6月25日
アルゴリズムとデータ構造 2012年6月21日
Javaとは Javaとはオブジェクト指向言語でJava VM(Java仮想マシン)と呼ばれるプログラム上で動作します。
データ構造と アルゴリズム 第四回 知能情報学部 新田直也.
プログラミング入門2 第5回 配列 変数宣言、初期化について
オブジェクト指向 プログラミング 第六回 知能情報学部 新田直也.
情報処理Ⅱ 小テスト 2005年2月1日(火).
TList リスト構造とは? 複数のデータを扱うために、 データの内容と、次のデータへのポインタを持つ構造体を使う。
計算機プログラミングI 第2回 2002年10月17日(木) 履習登録 複習 ライブラリの利用 (2.6-7) 式・値・代入 (2.6-8)
計算機プログラミングI 第5回 2002年11月7日(木) 配列: 沢山のデータをまとめたデータ どんなものか どうやって使うのか
アルゴリズムとデータ構造 2012年7月9日
Presentation transcript:

最短経路

最短経路 有向グラフのstart点から与えられたgoal点までの最短の経路を求める。ここでは、各辺の長さは1とする。 点の数はn。各点は0~n-1の番号で参照。 for (int i = 0; i < n; i++) step[i] = -1; step[start] = 0; for (int s = 0; step[goal] == -1; s++) for (step[i]==sを満たす各iについて) for (iと隣接する各kについて) if (step[k] == -1) { step[k] = s+1; prev[k] = i; }

public class Node() { int value; Node next; public Node(int x, Node n) { value = x; next = n; } public class Shortest { static int[][] edges = ...; static int n = edges.length; static int[] step = new int[n]; static int[] prev = new int[n]; static Node q0, q1;

static void shortest(int start, int goal) { for (int i = 0; i < n; i++) step[i] = -1; step[start] = 0; q0 = new Node(start, null); for (int s = 0; step[goal] == -1; s++) { while (q0 != null) { int i = q0.value; int[] e = edges[i]; for (int j = 0; j < e.length; j++) { int k = e[j]; if (step[k] == -1) { step[k] = s+1; q1 = new Node(k, q1); prev[k] = i; } q0 = q0.next; q0 = q1;

public static void main(String[] args) { shortest(0, 9); for (int i = 9; i != 0; i = prev[i]) System.out.println(i); }

static int[][] edges = { {1,2,3}, {6}, {4,5,6}, {2}, {7}, {9}, {8,9}, {7,9}, {}}; 3 4 2 5 1 7 9 6 8

3 4 s = 0 2 5 1 7 9 6 8

3 4 s = 1 2 5 1 7 9 6 8

3 4 s = 2 2 5 1 7 9 6 8

3 4 s = 3 2 5 1 7 9 6 8

配列の配列 配列の配列は次のように宣言・生成する。 int[][] a = new int[5][3]; 個々のa[i]は配列である。 int[] b; b = a[3]; 従って、各要素はa[i][j] と参照する。

配列の配列(続き) 個々のa[i]は空(null)でもよい。 int[][] a = new int[5][]; 個々のa[i]には、 大きさの異なる配列も 設定できる。 a[1] = new int[3]; a[2] = new int[2];

配列の配列(最後) 配列は生成時に初期化できる。 int[][] a = {null, {1,2,3}, {4,5}, null, null}; 1 2 3 4 5

最短経路(Dijkstra法)

Dijkstra法 有向グラフのstart点からgoal点までの最短の経路を求める。 点の数はn。各点は0~n-1の番号で参照。 for (int i = 0; i < n; i++) dist[i] = ∞; dist[start] = 0; pool = startのみからなる集合; while (true) { poolの中でdist[i]が最小のものをiとする; poolからiを除く; if (i == goal) break; for (iと隣接する各kについて) if (dist[i] + (iからkへの距離) < dist[k]) { dist[k] = dist[i] + (iからkへの距離): prev[k] = i; kをpoolに加える; } ここで停止しなければ、start点から任意の点までの最短経路が求まる。その場合、ループの条件を while (pool != 空) とする。

public class Dijkstra { static int[][] edges = ...; static int[][] lengths = ...; static int n = edges.length; static int[] dist = new int[n]; static int[] prev = new int[n]; static ... pool;

static void shortest(int start, int goal) { for (int i = 0; i < n; i++) dist[i] = 999999; dist[start] = 0; pool = startのみからなる集合; while (true) { int i = poolの中でdist[i]が最小のもの; poolからiを除く; if (i == goal) break; int[] e = edges[i]; for (int j = 0; j < e.length; j++) { int k = e[j]; if (dist[i] + lengths[i][j] < dist[k]) { dist[k] = dist[i] + lengths[i][j]; prev[k] = i; poolにkを追加; }

poolを配列で実装する場合 static int poolsize = 0; static int[] poolarray = ... static void shortest(int start, int goal) { for (int i = 0; i < n; i++) dist[i] = 999999; dist[start] = 0; poolarray[0] = start; poolsize = 1; while (true) { int i; int m = 999999; for (int p = 0; p < poolsize; p++) if (dist[poolarray[p]] < m) { i = p; m = dist[poolarray[p]]; } poolからiを除く; if (i == goal) break; int[] e = edges[i]; for (int j = 0; j < e.length; j++) { int k = e[j]; if (dist[i] + lengths[i][j] < dist[k]) { dist[k] = dist[i] + lengths[i][j]; prev[k] = i; if (poolarray[p] == k) { k = -1; break; } if (k >= 0) { poolarray[poolsize] = k; poolsize++; } }

public static void main(String[] args) { shortest(0, 9); for (int i = 9; i != 0; i = prev[i]) System.out.println(i); }

2 1 3 4 3 3 6 8 3 3 4 4 5 5 3 static int[][] edges = { {1,2,3}, 3 {6}, {4,5,6}, {2}, {7}, {9}, {8,9}, {7,9}, {}}; 3 2 1 4 3 4 2 3 3 6 5 1 8 static int[][] lengths = { {3,4,2}, {3}, {3,3,8}, {1}, {6}, {4}, {5,4}, {5,3}, {}}; 3 3 7 4 9 6 4 5 5 3 8

3 pool: 2 1 4 3 4 0 (0) 2 3 3 6 5 1 8 3 3 7 4 9 6 4 5 5 3 8

3 pool: 2 1 4 3 4 3 (2) 1 (3) 2 (4) 2 3 3 6 5 1 8 3 3 7 4 9 6 4 5 5 3 8

3 pool: 2 1 4 3 4 2 (3) 1 (3) 2 3 3 6 5 1 8 3 3 7 4 9 6 4 5 5 3 8

3 pool: 2 1 4 3 4 1 (3) 5 (6) 4 (6) 6 (11) 2 3 3 6 5 1 8 3 3 7 4 9 6 4 5 5 3 8

3 pool: 2 1 4 3 4 6 (6) 5 (6) 4 (6) 2 3 3 6 5 1 8 3 3 7 4 9 6 4 5 5 3 8

3 pool: 2 1 4 3 4 5 (6) 4 (6) 9 (10) 2 3 3 6 5 1 8 3 3 7 4 9 6 4 5 5 3 8

3 pool: 2 1 4 3 4 4 (6) 9 (9) 2 3 3 6 5 1 8 3 3 7 4 9 6 4 5 5 3 8

3 pool: 2 1 4 3 4 9 (9) 7 (12) 2 3 3 6 5 1 8 3 3 7 4 9 6 4 5 5 3 8

計算量 いったんpoolから除かれた点は、 二度とpoolには入らない(辺の長さが非負ならば)。 内側のループは辺の数mだけ回る。 外側は点の数nだけ回るが、通常はm>nなので無視。 poolの各操作が点の数nに比例するならば、O(mn)。 例えば、リストによってpoolを実装した場合。 ヒープと呼ばれるデータ構造を用いると、 各操作をlog nに比例した時間で処理可能。 全体の計算量は、O(m log n)となる。 さらにフィボナッチ・ヒープと呼ばれるデータ構造を 用いると、全体の計算量は、O(m+n log n)となる。

ヒープの適用 配列aに挿入するのは、グラフの点の番号。 比較は、distを参照して行えばよい。 a[j]<a[j/2-1]  dist[a[j]]<dist[a[j/2-1]]

ヒープの適用 decrease_keyを行うためには、グラフの各点に対して、 ヒープの配列aの要素で、その点が入っている要素の インデックスを対応させる配列を 用意しなければならない。 int[] index; index[v]は点vが入っているaの要素のインデックス。 index[v]がiに等しいならば、a[i]はvに等しい。 この配列の要素は-1で初期化してやる。 vがヒープから除かれるとindex[v]は-1にもどる。 index[v]が-1に等しければ、ヒープにないということ。

ヒープの適用 insertはindexも変更する必要があるので以下のようになる。 static void insert(int v) { a[n] = v; index[v] = n; for (int j = n; j>0 && dist[a[j]]<dist[a[(j-1)/2]]; j = (j-1)/2) { int w = a[j]; a[j] = a[(j-1)/2]; a[(j-1)/2] = w; index[a[j]] = j; index[a[(j-1)/2] = (j-1)/2; } n++;

ヒープの適用 distが優先度を保持しているので、 decrease_keyはグラフの点のみを 引数とすればよい。 static void decrease_key(int v) { ... }

二次元グラフィクス import java.awt.*; import javax.swing.*; class GraphPanel extends JPanel { int[][] edges; int[] x; int[] y; int[] prev; int start; int goal;

GraphPanel(int[][] edges, int[] x, int[] y, int[] prev, int start, int goal) { this.edges = edges; this.x = x; this.y = y; this.prev = prev; this.start = start; this.goal = goal; setBackground(Color.white); setMinimumSize(new Dimension(900, 500)); setPreferredSize(new Dimension(900, 500)); }

public void paintComponent(Graphics g){ super.paintComponent(g); g.setColor(Color.BLACK); for (int i = 0; i < edges.length; i++) for (int j = 0; j < edges[i].length; j++) { g.drawLine(x[i], y[i],    x[edges[i][j]], y[edges[i][j]]); } if (prev != null) { g.setColor(Color.RED); for (int i = goal; i != start; i = prev[i]) {    x[prev[i]], y[prev[i]]);

public static void main(String[] args) { N01_07L_13.init(); JFrame f = new JFrame("Draw Example"); GraphPanel example = new GraphPanel(N01_07L_13.edges, N01_07L_13.x, N01_07L_13.y, null, 0, 0); f.getContentPane().add(example, BorderLayout.CENTER); f.pack(); f.setVisible(true); }

演習 GraphPanel.javaおよびN01_07L_13.javaを コンパイルして、GraphPanel.mainを実行 してみよ。

Dijkstraのプログラムへの組み込み 例えば、mainを次のようにする。

public static void main(String[] args) { N01_07L_13.init(); edges = N01_07L_13.edges; lengths = N01_07L_13.lengths; x = N01_07L_13.x; y = N01_07L_13.y; n = edges.length; dist = new int[n]; prev = new int[n]; shortest(100, 1500); JFrame f = new JFrame("Draw Example"); GraphPanel example = new GraphPanel(edges, x, y, prev, 100, 1500); f.getContentPane().add(example, BorderLayout.CENTER); f.pack(); f.setVisible(true); }

注意 N01_07L_13において、任意の2点間が 連結であるとは限らない。