先日、Boost.勉強会 #14 東京に参加させて頂いたが、そこでBoost.Graphの話があった。
復習がてら、今回はTDD Boot Camp 東京 for C++での最短経路探索の課題(TDD Boot Camp 東京 for C++ 課題)をBoost.Graphで解いてみる。なお課題は規模が大きいので、今回は横浜近辺の5駅に絞った。
グラフ構造の構築
まずBoost.Graphでグラフ構造を記述する。
なおBoost.Graphはgraphvizのグラフ図を出力できるので、今回は記述したグラフ構造をgraphvizで画像化して視覚的に確認する。コードは以下。
#include <iostream> #include <vector> #include <boost/graph/adjacency_list.hpp> #include <fstream> #include <boost/graph/graphviz.hpp> using namespace boost; typedef adjacency_list<listS, vecS, undirectedS, no_property, property<edge_weight_t, int>> Graph; typedef std::pair<int, int> Edge; typedef graph_traits<Graph>::vertex_descriptor Vertex; //駅の定義 enum { Yokohama, MusashiKosugi, Kawasaki, Shibuya, Tokyo, N }; const char* NameList[] = { "Yokohama", "MusashiKosugi", "Kawasaki", "Shibuya", "Tokyo" }; int main() { //経路と所要時間の定義 const std::vector<Edge> edges = { {Yokohama, MusashiKosugi}, {Yokohama, Kawasaki}, {MusashiKosugi, Kawasaki}, {MusashiKosugi, Shibuya}, {Kawasaki, Tokyo}, {Shibuya, Tokyo} }; const std::vector<int> weights = { 23, 14, 19, 21, 24, 25 }; const Graph g(edges.begin(), edges.end(), weights.begin(), N); std::ofstream file("trainpath.dot"); write_graphviz(file, g, make_label_writer(NameList)); return 0; }
上記のコードを実行した後、生成されたgraphvizのdotファイルを「dot -Tpng trainpath.dot -o trainpath.png」などのコマンドでpngに変換する。すると以下の様な画像が得られる。
最短経路検索
グラフ構造を記述できたら、今回は横浜・東京間の最短経路をダイクストラ法を使って導き出す。
コードは以下。
#include <iostream> #include <vector> #include <deque> #include <boost/graph/adjacency_list.hpp> #include <boost/graph/dijkstra_shortest_paths.hpp> using namespace boost; typedef adjacency_list<listS, vecS, undirectedS, no_property, property<edge_weight_t, int>> Graph; typedef std::pair<int, int> Edge; typedef graph_traits<Graph>::vertex_descriptor Vertex; //駅の定義 enum { Yokohama, MusashiKosugi, Kawasaki, Shibuya, Tokyo, N }; const char* NameList[] = { "Yokohama", "MusashiKosugi", "Kawasaki", "Shibuya", "Tokyo" }; int main() { //経路と所要時間 const std::vector<Edge> edges = { {Yokohama, MusashiKosugi}, {Yokohama, Kawasaki}, {MusashiKosugi, Kawasaki}, {MusashiKosugi, Shibuya}, {Kawasaki, Tokyo}, {Shibuya, Tokyo} }; const std::vector<int> weights = { 23, 14, 19, 21, 24, 25 }; //最短経路の探索 const Graph g(edges.begin(), edges.end(), weights.begin(), N); const Vertex from = Yokohama; const Vertex to = Tokyo; std::vector<Vertex> parents(num_vertices(g)); std::vector<std::size_t> distance(num_vertices(g)); dijkstra_shortest_paths(g, from, predecessor_map(&parents[0]).distance_map(&distance[0])); //探索結果をリスト化 std::deque<Vertex> route; for (Vertex v = to; v != from; v = parents[v]) { route.push_front(v); } route.push_front(from); for (const Vertex v : route) { std::cout << NameList[v] << std::endl; } return 0; }
これを実行すると最短経路が以下のようにリストアップされる。
Yokohama Kawasaki Tokyo
また最短経路の時間は、上記のコードの場合distance[to]に格納されている。また今回はグラフ構造が自明だったため今回は省いているけれど、経路が存在しないことは「parents[to] == to」が真となることの確認で判定できる。