2011 711 sakai keiichikochitech ac jp http www

  • Slides: 16
Download presentation
アルゴリズムとデータ構造 2011年 7月11日 酒居敬一(sakai. keiichi@kochi-tech. ac. jp) http: //www. info. kochi-tech. ac. jp/k 1

アルゴリズムとデータ構造 2011年 7月11日 酒居敬一(sakai. keiichi@kochi-tech. ac. jp) http: //www. info. kochi-tech. ac. jp/k 1 sakai/Lecture/ALG/2011/index. html 1

public class Weighted. Node<E> { 辺に重みを持たせるため、Mapを使う。 private E value; // 頂点の値 private Map<Weighted. Node<E>,

public class Weighted. Node<E> { 辺に重みを持たせるため、Mapを使う。 private E value; // 頂点の値 private Map<Weighted. Node<E>, Integer> edges; // 有向辺 private boolean visited; 出発点からの距離 private int distance; public Weighted. Node(E value, Map<Weighted. Node<E>, Integer> edges) { this. value = value; this. edges = edges; 辺の重み reset(); } public void reset(){ this. visited = false; this. distance = Integer. MAX_VALUE; this. edges. clear(); } public E get. Value() { // 頂点の値を得る。 return value; } public Map<Weighted. Node<E>, Integer> get. Edges(){ return this. edges; } // アクセッサは、このスライドでは省略した。実際には存在する。 public void connect. To(Weighted. Node<E> to, int weight){ this. edges. put(to, weight); // 有向辺を追加 } 本日使う頂点のデータ構造 } 4

public class Dijkstra { public static <E> void search(Collection<Weighted. Node<E>> graph, Weighted. Node<E> start){

public class Dijkstra { public static <E> void search(Collection<Weighted. Node<E>> graph, Weighted. Node<E> start){ Set<Weighted. Node<E>> visited = new Hash. Set<Weighted. Node<E>>(); 集合V Set<Weighted. Node<E>> unreached = new Hash. Set<Weighted. Node<E>>(graph); start. set. Distance(0); while( !unreached. is. Empty() ){ int min_distance = Integer. MAX_VALUE; Weighted. Node<E> min_node = null; 集合U for(Weighted. Node<E> node: unreached){ if(node. get. Distance() < min_distance){ min_distance = node. get. Distance(); 集合Uから最小の距離をもつ頂点を探索 min_node = node; } } unreached. remove(min_node); visited. add(min_node); for(Map. Entry<Weighted. Node<E>, Integer> edge: min_node. get. Edges(). entry. Set()){ if(unreached. contains(edge. get. Key())){ edge. get. Key(). set. Distance( Math. min(edge. get. Key(). get. Distance(), min_node. get. Distance() + edge. get. Value())); } } 教科書263ページの擬似プログラムをJavaで実装 } 5

private static Weighted. Node<Character> node. A = new Weighted. Node<Character>('A', new Hash. Map<Weighted. Node<Character>,

private static Weighted. Node<Character> node. A = new Weighted. Node<Character>('A', new Hash. Map<Weighted. Node<Character>, Integer>()); private static Weighted. Node<Character> node. B = new Weighted. Node<Character>('B', new Hash. Map<Weighted. Node<Character>, Integer>()); private static Weighted. Node<Character> node. C = new Weighted. Node<Character>('C', new Hash. Map<Weighted. Node<Character>, Integer>()); private static Weighted. Node<Character> node. D = new Weighted. Node<Character>('D', new Hash. Map<Weighted. Node<Character>, Integer>()); private static Weighted. Node<Character> node. E = new Weighted. Node<Character>('E', new Hash. Map<Weighted. Node<Character>, Integer>()); private static Weighted. Node<Character> node. F = new Weighted. Node<Character>('F', new Hash. Map<Weighted. Node<Character>, Integer>()); private static Collection<Weighted. Node<Character>> test_data = new Linked. List<Weighted. Node<Character>>(); static { test_data. add(node. A); test_data. add(node. B); test_data. add(node. C); test_data. add(node. D); test_data. add(node. E); test_data. add(node. F); } public static void main(String[] args) { System. out. println("図 4. 5. 1"); for(Weighted. Node<Character> node: test_data){ node. reset(); } node. A. connect. To(node. B, 6); node. A. connect. To(node. C, 4); node. B. connect. To(node. D, 3); node. C. connect. To(node. E, 3); node. C. connect. To(node. F, 6); node. E. connect. To(node. B, 2); node. E. connect. To(node. D, 1); search(test_data, node. A); System. out. println("頂点" + node. A. get. Value() + "からの距離"); for(Weighted. Node<Character> node: test_data){ System. out. println("頂点" + node. get. Value() + ": " + node. get. Distance()); } } ひとつずつ確定する作戦の前提として、 辺の重みは正の値である。 図 4. 5. 1 頂点Aからの距離 頂点A: 0 頂点B: 6 頂点C: 4 頂点D: 8 頂点E: 7 頂点F: 10 6

public class Dijkstra. Array { public static <E> void search(Weighted. Node<E>[] nodes, int start,

public class Dijkstra. Array { public static <E> void search(Weighted. Node<E>[] nodes, int start, int[][] weights){ nodes[start]. set. Distance(0); for(int step = 0; step < nodes. length; step++){ 頂点の配列と、頂点同士の接続行列 int min = Integer. MAX_VALUE; int p = 0; for(int x = 0; x < nodes. length; x++){ if( !nodes[x]. is. Visited() && (nodes[x]. get. Distance() < min)){ p = x; min = nodes[x]. get. Distance(); } } if(min == Integer. MAX_VALUE){ throw new Illegal. Argument. Exception("グラフが連結でない。"); } nodes[p]. set. Visited(true); for(int x = 0; x < nodes. length; x++){ if(weights[p][x] == Integer. MAX_VALUE){ continue; } nodes[x]. set. Distance( Math. min(nodes[x]. get. Distance(), nodes[p]. get. Distance() + weights[p][x])); } } 265ページのプログラムのJava実装 } 8 }

private static Weighted. Node<Character> node. A = new Weighted. Node<Character>('A'); private static Weighted. Node<Character>

private static Weighted. Node<Character> node. A = new Weighted. Node<Character>('A'); private static Weighted. Node<Character> node. B = new Weighted. Node<Character>('B'); private static Weighted. Node<Character> node. C = new Weighted. Node<Character>('C'); private static Weighted. Node<Character> node. D = new Weighted. Node<Character>('D'); private static Weighted. Node<Character> node. E = new Weighted. Node<Character>('E'); private static Weighted. Node<Character> node. F = new Weighted. Node<Character>('F'); @Suppress. Warnings("unchecked") private static Weighted. Node<Character>[] test_data = new Weighted. Node[] { node. A, node. B, node. C, node. D, node. E, node. F }; public static void main(String[] args) { System. out. println("図 4. 5. 1"); for(Weighted. Node<Character> node: test_data){ node. reset(); } int[][] weights = new int[test_data. length]; for(int[] from: weights){ for(int i = 0; i < from. length; i++){ from[i] = Integer. MAX_VALUE; } } weights[0][1] = 6; これもDijkstraのアルゴリズムなので、 weights[0][2] = 4; weights[1][3] = 3; ひとつずつ確定する作戦の前提として、 weights[2][4] = 3; 辺の重みは正の値である。 weights[2][5] = 6; weights[4][1] = 2; weights[4][3] = 1; search(test_data, 0, weights); System. out. println("頂点" + node. A. get. Value() + "からの距離"); for(Weighted. Node<Character> node: test_data){ System. out. println("頂点" + node. get. Value() + ": " + node. get. Distance()); } } 図 4. 5. 1 頂点Aからの距離 頂点A: 0 頂点B: 6 頂点C: 4 頂点D: 8 頂点E: 7 頂点F: 10 9

public class Floyd { public static <E> void search(int[][] weights, int[][] distances){ for(int i

public class Floyd { public static <E> void search(int[][] weights, int[][] distances){ for(int i = 0; i < weights. length; i++){ distances[i] = weights[i]. clone(); } for(int k = 0; k < weights. length; k++){ for(int i = 0; i < weights. length; i++){ if(distances[i][k] == Integer. MAX_VALUE){ continue; // 未接続 or 未計算 } for(int j = 0; j < weights[i]. length; j++){ if(distances[k][j] == Integer. MAX_VALUE){ continue; // 未接続 or 未計算 } int w = distances[i][k] + distances[k][j]; if(w < distances[i][j]){ distances[i][j] = w; } } 頂点kを経由して、頂点iから頂点jに至る道があれば、 } 距離をあらわす行列にその距離を計算し格納する。 } } } 270ページのプログラム Floydのアルゴリズム 11

public static void main(String[] args) { System. out. println("図 4. 5. 1"); int[][] weights

public static void main(String[] args) { System. out. println("図 4. 5. 1"); int[][] weights = new int[6][6]; for(int i = 0; i < weights. length; i++){ for(int j = 0; j < weights[i]. length; j++){ weights[i][j] = Integer. MAX_VALUE; } weights[i][i] = 0; } weights[0][1] = 6; weights[0][2] = 4; weights[1][3] = 3; weights[2][4] = 3; weights[2][5] = 6; weights[4][1] = 2; weights[4][3] = 1; int[][] distances = new int[weights. length][]; search(weights, distances); System. out. println("頂点間の距離"); for(int i = 0; i < distances. length; i++){ for(int j = 0; j < distances[i]. length; j++){ if(distances[i][j] == Integer. MAX_VALUE){ System. out. print("- "); } else { System. out. print(distances[i][j] + " "); } } System. out. println(); } } 図 4. 5. 1 頂点間の距離 0 6 4 8 7 10 - 3 - - 5 0 4 3 6 - - - 0 - - 2 - 1 0 - - - 0 12

public class Warshall { public static <E> void search(boolean[][] adjacency, boolean[][] reachable){ for(int i

public class Warshall { public static <E> void search(boolean[][] adjacency, boolean[][] reachable){ for(int i = 0; i < adjacency. length; i++){ reachable[i] = adjacency[i]. clone(); } for(int k = 0; k < adjacency. length; k++){ 入力は隣接行列 for(int i = 0; i < adjacency. length; i++){ if( !reachable[i][k] ){ continue; } for(int j = 0; j < adjacency[i]. length; j++){ 出力は推移的閉包 reachable[i][j] = reachable[i][j] || reachable[k][j]; } } } 14

public static void main(String[] args) { System. out. println("図 4. 5. 1"); boolean[][] adjacency

public static void main(String[] args) { System. out. println("図 4. 5. 1"); boolean[][] adjacency = new boolean[6][6]; for(int i = 0; i < adjacency. length; i++){ for(int j = 0; j < adjacency[i]. length; j++){ adjacency[i][j] = false; } adjacency[i][i] = true; } adjacency[0][1] = true; adjacency[0][2] = true; adjacency[1][3] = true; adjacency[2][4] = true; adjacency[2][5] = true; adjacency[4][1] = true; adjacency[4][3] = true; boolean[][] reachable = new boolean[adjacency. length][]; search(adjacency, reachable); System. out. println("推移的閉包"); for(int i = 0; i < reachable. length; i++){ for(int j = 0; j < reachable[i]. length; j++){ if(reachable[i][j]){ System. out. print("+ "); } else { System. out. print("- "); } } System. out. println(); } } 図 4. 5. 1 推移的閉包 + + + - + - - + + + - - - + - + + - - - + 15