/// <summary> /// 有向グラフの強連結成分を判定する /// </summary> /// <param name="graph">グラフ</param> /// <returns>ノード→クラスタID配列</returns> public static int[] Calc(DirectedAdjacencyList graph) { var results = Visit(graph); int[] cluster_array = AntiVisit(graph, results.invOrderArray); return(cluster_array); }
/// <summary> /// 正方向の後順探索で各接点に訪問する /// </summary> /// <param name="graph">グラフ</param> /// <returns>ノード→訪問順配列と、訪問順→ノード配列</returns> private static (int[] orderArray, int[] invOrderArray) Visit(DirectedAdjacencyList graph) { // 作業領域を確保 int[] order_array = new int[graph.NodeNum]; int[] inv_order_array = new int[graph.NodeNum]; for (int i = 0; i < graph.NodeNum; i++) { order_array[i] = UNVISITED; } int order = 0; Stack <int> visit_stack = new Stack <int>(graph.NodeNum); for (int i = 0; i < graph.NodeNum; i++) { // 未訪問のノードから始める if (order_array[i] != UNVISITED) { continue; } visit_stack.Clear(); visit_stack.Push(i); order_array[i] = VISITED; while (visit_stack.Count != 0) { int v = visit_stack.Peak(); // vから到達できる未訪問のノードに訪問する bool move = false; LinkList edgeList = graph.GetOutLinkedEdgeList(v); for (LinkNode node = edgeList.head; node != null; node = node.next) { int w = GraphUtil.GetOpposite(v, graph.EdgeList[node.data]); if (order_array[w] == UNVISITED) { visit_stack.Push(w); order_array[w] = VISITED; move = true; } } // どこにも移動できなかったら後順探索に従って番号付け if (!move) { visit_stack.Pop(); order_array[v] = order; inv_order_array[order] = v; order++; } } } return(order_array, inv_order_array); }
/// <summary> /// 逆方向の前順探索で各接点に訪問する /// </summary> /// <param name="graph">グラフ</param> /// <param name="invOrderArray">訪問順→ノード配列</param> /// <returns>ノード→クラスタID配列</returns> public static int[] AntiVisit(DirectedAdjacencyList graph, int[] invOrderArray) { int[] result = new int[graph.NodeNum]; for (int i = 0; i < result.Length; i++) { result[i] = UNVISITED; } int cluster_id = 0; Stack <int> visit_stack = new Stack <int>(graph.NodeNum); for (int i = 0; i < graph.NodeNum; i++) { // i番目に大きい訪問順を持つノードから始める int s = invOrderArray[(graph.NodeNum - 1) - i]; // 訪問済みならスキップ if (result[s] != UNVISITED) { continue; } visit_stack.Clear(); visit_stack.Push(s); result[s] = cluster_id; while (visit_stack.Count != 0) { int v = visit_stack.Pop(); // 反有向木において、vから到達できる未訪問のノードに訪問する LinkList edgeList = graph.GetInLinkedEdgeList(v); for (LinkNode node = edgeList.head; node != null; node = node.next) { int w = GraphUtil.GetOpposite(v, graph.EdgeList[node.data]); if (result[w] == UNVISITED) { visit_stack.Push(w); result[w] = cluster_id; } } } cluster_id++; } return(result); }
public void BasicTests() { var adjList = new DirectedAdjacencyList <int>(2); adjList.AddVertex(10); adjList.AddVertex(20); adjList.CreateEdge(10, 20); Assert.IsTrue(adjList.Adjacent(10, 20)); Assert.IsFalse(adjList.Adjacent(20, 10)); var undirectedList = new UndirectedAdjacenyList <int>(2); undirectedList.AddVertex(10); undirectedList.AddVertex(20); undirectedList.CreateEdge(10, 20); Assert.IsTrue(undirectedList.Adjacent(10, 20)); Assert.IsTrue(undirectedList.Adjacent(20, 10)); }
public static AdjacencyList ReadGraph(string filepath) { StreamReader reader = new StreamReader(filepath); int no_of_node = -1; int no_of_edge = -1; bool directed = false; while (!reader.EndOfStream) { string[] record = reader.ReadLine().Split(' '); // 1フィールド目が属性 switch (record[0]) { case "TYPE": directed = record[2] == "DIRECTED"; break; case "NO_OF_NODE": no_of_node = int.Parse(record[2]); break; case "NO_OF_EDGE": no_of_edge = int.Parse(record[2]); break; case "EDGE_CODE_SECTION": goto READ_EDGE_DATA; } } // エッジデータの読み込み READ_EDGE_DATA: if (no_of_node == -1) { Common.ErrorExit("ノード数の指定がありません。"); } if (no_of_edge == -1) { Common.ErrorExit("エッジ数の指定がありません。"); } int[][] edge_list = new int[no_of_edge][]; for (int i = 0; i < no_of_edge; i++) { if (reader.EndOfStream) { Common.ErrorExit("NO_OF_EDGEで指定されたエッジ数よりも少ないデータが記載されています。"); } string[] record = reader.ReadLine().Split(' '); edge_list[i] = new int[2]; edge_list[i][0] = int.Parse(record[0]); edge_list[i][1] = int.Parse(record[1]); } if (!reader.EndOfStream) { Common.ErrorExit("NO_OF_EDGEで指定されたエッジ数よりも多いデータが記載されています。"); } AdjacencyList instance; if (directed) { instance = new DirectedAdjacencyList(no_of_node, no_of_edge, edge_list); } else { instance = new UndirectedAdjacencyList(no_of_node, no_of_edge, edge_list); } return(instance); }