boost.graphでjr全線乗り尽くしプランを立てる -...

58
プログラミング生放送+CLR/H+Sapporo.cpp 勉強会@札幌 (2014.7.12) Boost.Graphで JR全線乗り尽くしプラン を立てる H.Hiro @ Sapporo.cpp Twitter: @h_hiro_ http://hhiro.net/about/

Upload: hiro-h

Post on 13-Jun-2015

2.188 views

Category:

Technology


2 download

TRANSCRIPT

Page 1: Boost.GraphでJR全線乗り尽くしプランを立てる - プログラミング生放送+CLR/H+Sapporo.cpp 勉強会@札幌 (2014.7.12)

プログラミング生放送+CLR/H+Sapporo.cpp 勉強会@札幌(2014.7.12)

Boost.GraphでJR全線乗り尽くしプラン

を立てる

H.Hiro @ Sapporo.cppTwitter: @h_hiro_

http://hhiro.net/about/

Page 2: Boost.GraphでJR全線乗り尽くしプランを立てる - プログラミング生放送+CLR/H+Sapporo.cpp 勉強会@札幌 (2014.7.12)

自己紹介

Page 3: Boost.GraphでJR全線乗り尽くしプランを立てる - プログラミング生放送+CLR/H+Sapporo.cpp 勉強会@札幌 (2014.7.12)

●某研究員(もう学生じゃありません)

●アルゴリズム作るのは本業です●趣味でもプログラム書いてます●C++とかRubyとか他にも何でも●最近はアマチュアサッカーの観戦とかも

Page 4: Boost.GraphでJR全線乗り尽くしプランを立てる - プログラミング生放送+CLR/H+Sapporo.cpp 勉強会@札幌 (2014.7.12)

ソースコードはこちらです

https://github.com/maraigue/cpp-chinese-postman

Page 5: Boost.GraphでJR全線乗り尽くしプランを立てる - プログラミング生放送+CLR/H+Sapporo.cpp 勉強会@札幌 (2014.7.12)

今回の内容

Page 6: Boost.GraphでJR全線乗り尽くしプランを立てる - プログラミング生放送+CLR/H+Sapporo.cpp 勉強会@札幌 (2014.7.12)

JR線全線を乗り尽くす

地図:国土数値情報 鉄道データ N02-08(2008年現在;JR以外の鉄道も入ってます)

Page 7: Boost.GraphでJR全線乗り尽くしプランを立てる - プログラミング生放送+CLR/H+Sapporo.cpp 勉強会@札幌 (2014.7.12)

鉄道ファンにとって一つのステータス

Page 8: Boost.GraphでJR全線乗り尽くしプランを立てる - プログラミング生放送+CLR/H+Sapporo.cpp 勉強会@札幌 (2014.7.12)

これをなるべく短い乗車距離で

実現したい

Page 9: Boost.GraphでJR全線乗り尽くしプランを立てる - プログラミング生放送+CLR/H+Sapporo.cpp 勉強会@札幌 (2014.7.12)

今回のルール

Page 10: Boost.GraphでJR全線乗り尽くしプランを立てる - プログラミング生放送+CLR/H+Sapporo.cpp 勉強会@札幌 (2014.7.12)

●単に乗り尽くしたら終わりではなく、「出発地点まで帰ってくる」までの乗車距離で考える

●出発地点まで戻るときも含めJR以外の交通機関は利用しないとする

Page 11: Boost.GraphでJR全線乗り尽くしプランを立てる - プログラミング生放送+CLR/H+Sapporo.cpp 勉強会@札幌 (2014.7.12)

予備知識

Page 12: Boost.GraphでJR全線乗り尽くしプランを立てる - プログラミング生放送+CLR/H+Sapporo.cpp 勉強会@札幌 (2014.7.12)

グラフ理論

Page 13: Boost.GraphでJR全線乗り尽くしプランを立てる - プログラミング生放送+CLR/H+Sapporo.cpp 勉強会@札幌 (2014.7.12)

●グラフ:状態(頂点 vertex, node)と、二つの状態を結ぶもの(辺 edge)からなるデータ構造(今回は駅が頂点、路線が辺)

●各辺には、通ることで加算される利益や損失の数値(重み)を与えることができる(今回は距離を重みとし損失とみなす)

桑園 札幌 苗穂 白石 平和

厚別八軒

琴似

22 16 22 36

4422

22

(辺の重みに書かれた 距離の単位は「0.1km」)

Page 14: Boost.GraphでJR全線乗り尽くしプランを立てる - プログラミング生放送+CLR/H+Sapporo.cpp 勉強会@札幌 (2014.7.12)

補足●今回は、JR線が3方向以上に分岐している駅のみ頂点とする。

●今回は、辺は両方向に行き来できるもののみ扱う(無向グラフ undirected graph)。一方通行は考えない

桑園 札幌 苗穂 白石 平和

厚別八軒

琴似

22 16 22 36

4422

22

(辺の重みに書かれた 距離の単位は「0.1km」)

Page 15: Boost.GraphでJR全線乗り尽くしプランを立てる - プログラミング生放送+CLR/H+Sapporo.cpp 勉強会@札幌 (2014.7.12)

Boost.Graph

Page 16: Boost.GraphでJR全線乗り尽くしプランを立てる - プログラミング生放送+CLR/H+Sapporo.cpp 勉強会@札幌 (2014.7.12)

Boost.Graph:グラフ構造を扱うライブラリ// 無向グラフを扱うために必要なものをインクルード#include <boost/graph/undirected_graph.hpp>// グラフの型の定義。// 頂点から出る辺の一覧はstd::vector、頂点の一覧はstd::set、// 無向グラフ、頂点には駅名、辺にはint型で重みを付与typedef boost::adjacency_list<boost::vecS, boost::setS,

boost::undirectedS,boost::property<boost::vertex_name_t, std::string>,boost::property<boost::edge_weight_t, int> > Graph;

// 続く

Page 17: Boost.GraphでJR全線乗り尽くしプランを立てる - プログラミング生放送+CLR/H+Sapporo.cpp 勉強会@札幌 (2014.7.12)

Boost.Graph:グラフ構造を扱うライブラリ// 続きint main(void){ Graph g; // 頂点を追加 vertex_descriptor v1 = boost::add_vertex("桑園", g); vertex_descriptor v2 = boost::add_vertex("白石", g); // 辺を追加 // 第3パラメータは辺の属性(ここでは重み=距離) edge_descriptor e1 = boost::add_edge(v1, v2, 74, g);}

Page 18: Boost.GraphでJR全線乗り尽くしプランを立てる - プログラミング生放送+CLR/H+Sapporo.cpp 勉強会@札幌 (2014.7.12)

実際のコードを見てみましょう

Page 19: Boost.GraphでJR全線乗り尽くしプランを立てる - プログラミング生放送+CLR/H+Sapporo.cpp 勉強会@札幌 (2014.7.12)

// 駅名をキー、頂点を値とする連想配列std::map<std::string, RouteNetwork::vertex_descriptor> names2vertices;

while(!(ifs.eof())){ // (中略:ここで行を読み込む) // s[0] と s[1] に地点名が、 distance に距離が入る // 頂点を追加(まだ存在していないなら) for(size_t i = 0; i <= 1; ++i){ it = names2vertices.find(s[i]); if(it == names2vertices.end()){ vd[i] = boost::add_vertex(s[i], *this); names2vertices.insert(std::make_pair(s[i], vd[i])); }else{ vd[i] = it->second; } } // 辺を追加 boost::add_edge(vd[0], vd[1], distance, *this); total_distance += distance;}

Page 20: Boost.GraphでJR全線乗り尽くしプランを立てる - プログラミング生放送+CLR/H+Sapporo.cpp 勉強会@札幌 (2014.7.12)

今回の問題設定

Page 21: Boost.GraphでJR全線乗り尽くしプランを立てる - プログラミング生放送+CLR/H+Sapporo.cpp 勉強会@札幌 (2014.7.12)

今回の問題は、グラフ理論の用語で言えば●無向グラフが与えられたとき●すべての辺を少なくとも1回通る始点と終点が同一である経路で

●経路の辺の重みの総和が最小になるものを求めよ。

Page 22: Boost.GraphでJR全線乗り尽くしプランを立てる - プログラミング生放送+CLR/H+Sapporo.cpp 勉強会@札幌 (2014.7.12)

ちなみにこの問題は「中国人郵便配達問題」って名前が付いてます

Page 23: Boost.GraphでJR全線乗り尽くしプランを立てる - プログラミング生放送+CLR/H+Sapporo.cpp 勉強会@札幌 (2014.7.12)

なお、Wikipediaの「中国人郵便配達問題」を書いた"Sinryow"は

私です

Page 24: Boost.GraphでJR全線乗り尽くしプランを立てる - プログラミング生放送+CLR/H+Sapporo.cpp 勉強会@札幌 (2014.7.12)

もう少しグラフ理論について

必要なことを解説します

Page 25: Boost.GraphでJR全線乗り尽くしプランを立てる - プログラミング生放送+CLR/H+Sapporo.cpp 勉強会@札幌 (2014.7.12)

今回用いるグラフ理論の概念(1)

Page 26: Boost.GraphでJR全線乗り尽くしプランを立てる - プログラミング生放送+CLR/H+Sapporo.cpp 勉強会@札幌 (2014.7.12)

225

34

236

628

橋:その辺1本が消えることで路線網が分断される(非連結になる)ような辺

函館

大沼

森 長万部

1256五稜郭

中小国

↓青森

↑三厩

↑桑園

↓東室蘭

353 ━━━━ :橋━━━━ :橋でない

Page 27: Boost.GraphでJR全線乗り尽くしプランを立てる - プログラミング生放送+CLR/H+Sapporo.cpp 勉強会@札幌 (2014.7.12)

橋:その辺1本が消えることで路線網が分断される(非連結になる)ような辺➔橋は明らかに2回通らないとならない(全路線を通って出発地点に 戻る必要があるため)

Page 28: Boost.GraphでJR全線乗り尽くしプランを立てる - プログラミング生放送+CLR/H+Sapporo.cpp 勉強会@札幌 (2014.7.12)

今回用いるグラフ理論の概念(2)

オイラーグラフ

Page 29: Boost.GraphでJR全線乗り尽くしプランを立てる - プログラミング生放送+CLR/H+Sapporo.cpp 勉強会@札幌 (2014.7.12)

オイラーグラフ:スタート地点から一筆書き(全ての辺をちょうど1回ずつ通る経路)でスタート地点に戻ることのできるグラフオイラーグラフでない(一筆書きはできるけど) オイラーグラフである

Page 30: Boost.GraphでJR全線乗り尽くしプランを立てる - プログラミング生放送+CLR/H+Sapporo.cpp 勉強会@札幌 (2014.7.12)

なぜオイラーグラフを考える?➔もしJRの路線網がオイラーグラフなら、単に一筆書きになる(各区間1回ずつ通る)ように辿るのが最短経路なのは明らか。

➔ただ現実には、2回通らないとならない区間が存在する。【補足】いかなる区間も1回か2回通ればよく、3回通る必要はない。(証明は省略)

Page 31: Boost.GraphでJR全線乗り尽くしプランを立てる - プログラミング生放送+CLR/H+Sapporo.cpp 勉強会@札幌 (2014.7.12)

なぜオイラーグラフを考える?➔2回通ったところに辺が2本存在すると仮定してオイラーグラフになれば全線乗り尽して出発地点に戻れる。

➔2回通る区間を極力少なくすればよい。

オイラーグラフでない オイラーグラフである

ここを2本に増やす

Page 32: Boost.GraphでJR全線乗り尽くしプランを立てる - プログラミング生放送+CLR/H+Sapporo.cpp 勉強会@札幌 (2014.7.12)

オイラーグラフの特性●グラフのすべての頂点について、繋がっている辺の数(次数)が偶数ならばオイラーグラフである。逆も成り立つ。

●一部の辺を2本に増やし、上記の条件を満たせるようにすればよい。オイラーグラフでない オイラーグラフである

次数3

次数3

次数2

次数2

次数2 次数2

次数2

次数2

次数4

次数4

Page 33: Boost.GraphでJR全線乗り尽くしプランを立てる - プログラミング生放送+CLR/H+Sapporo.cpp 勉強会@札幌 (2014.7.12)

問題の解き方

Page 34: Boost.GraphでJR全線乗り尽くしプランを立てる - プログラミング生放送+CLR/H+Sapporo.cpp 勉強会@札幌 (2014.7.12)

1.橋を見つけて個別のグラフに切り離す。橋は「2回通る」と結論付ける。

函館

五稜郭

中小国

大沼

長万部

室蘭東室蘭

苫小牧

沼ノ端追分

新得夕張新夕張

東釧路

根室南千歳

新千歳空港

桑園 白石

新十津川

増毛

滝川

深川

旭川 新旭川

稚内

富良野

様似

岩見沢

Page 35: Boost.GraphでJR全線乗り尽くしプランを立てる - プログラミング生放送+CLR/H+Sapporo.cpp 勉強会@札幌 (2014.7.12)

1.橋を見つけて個別のグラフに切り離す。橋は「2回通る」と結論付ける。

函館

五稜郭

中小国

大沼

長万部

室蘭東室蘭

苫小牧

沼ノ端追分

新得夕張新夕張

東釧路

根室南千歳

新千歳空港

桑園 白石

新十津川

増毛

滝川

深川

旭川 新旭川

稚内

富良野

様似

岩見沢

Page 36: Boost.GraphでJR全線乗り尽くしプランを立てる - プログラミング生放送+CLR/H+Sapporo.cpp 勉強会@札幌 (2014.7.12)

橋を検出するアルゴリズムhttp://nupioca.hatenadiary.jp/entry/2013/11/03/200006●アルゴリズム自体はシンプルです●逆に、何でこのアルゴリズムでうまくいくのかが不思議です(私も理解してません)

Page 37: Boost.GraphでJR全線乗り尽くしプランを立てる - プログラミング生放送+CLR/H+Sapporo.cpp 勉強会@札幌 (2014.7.12)

2.次数2以下の頂点を削除し辺を統合する。(やらなくてもいいけど効率化のために)

894 新得254 新夕張追分

↓沼ノ端

↑岩見沢↑富良野

↓東釧路

←南千歳

夕張

橋のため削除

Page 38: Boost.GraphでJR全線乗り尽くしプランを立てる - プログラミング生放送+CLR/H+Sapporo.cpp 勉強会@札幌 (2014.7.12)

2.次数2以下の頂点を削除し辺を統合する。(やらなくてもいいけど効率化のために)

新得254+894=1148追分

↓沼ノ端

↑岩見沢↑富良野

↓東釧路

←南千歳

夕張

橋のため削除

Page 39: Boost.GraphでJR全線乗り尽くしプランを立てる - プログラミング生放送+CLR/H+Sapporo.cpp 勉強会@札幌 (2014.7.12)

2.次数2以下の頂点を削除し辺を統合する。(やらなくてもいいけど効率化のために)

函館

五稜郭

中小国

大沼

長万部

室蘭東室蘭

苫小牧

沼ノ端追分

新得夕張新夕張

東釧路

根室南千歳

新千歳空港

桑園 白石

新十津川

増毛

滝川

深川

旭川 新旭川

稚内

富良野

様似

岩見沢

Page 40: Boost.GraphでJR全線乗り尽くしプランを立てる - プログラミング生放送+CLR/H+Sapporo.cpp 勉強会@札幌 (2014.7.12)

2.次数2以下の頂点を削除し辺を統合する。(やらなくてもいいけど効率化のために)

沼ノ端追分

新得南千歳

白石

滝川旭川

富良野

岩見沢

Page 41: Boost.GraphでJR全線乗り尽くしプランを立てる - プログラミング生放送+CLR/H+Sapporo.cpp 勉強会@札幌 (2014.7.12)

Boost.Graphだとこんな具合// ---------- 変数宣言類は大幅に省略してます ----------std::pair<vertex_iterator, vertex_iterator> vertex_range = boost::vertices(*this);

for(vertex_iterator itv = vertex_range.first; itv != vertex_range.second; ++itv){ if(out_degree(*itv, *this) == 2){ // 次数が2の頂点があったら // 隣接する頂点と辺を覚えておき std::pair<out_edge_iterator, out_edge_iterator> edge_range = boost::out_edges(*itv, *this); for(out_edge_iterator ite = edge_range.first; ite != edge_range.second; ++ite, ++i){ sides[i] = vertex_target(*itv, *ite); distance += boost::get(boost::edge_weight, *this, *ite); links[i] = *ite; } // 元の辺を取り除くとともに新しく辺を加える boost::add_edge(sides[0], sides[1], distance, *this); boost::remove_edge(links[0], *this); boost::remove_edge(links[1], *this); }}

Page 42: Boost.GraphでJR全線乗り尽くしプランを立てる - プログラミング生放送+CLR/H+Sapporo.cpp 勉強会@札幌 (2014.7.12)

3. (どこの辺を2本に増やすか決めたい)

分割された各グラフについて、「すべての頂点の組に対する最短距離」を求める

白 岩 滝 旭 富 新 南 沼 追

追沼ノ端

追分

新得南千歳

白石

滝川旭川

富良野

岩見沢

Page 43: Boost.GraphでJR全線乗り尽くしプランを立てる - プログラミング生放送+CLR/H+Sapporo.cpp 勉強会@札幌 (2014.7.12)

白 岩 滝 旭 富 新 南 沼 追

この問題には「フロイド=ワーシャル法」という有名なアルゴリズムがあってBoost.Graphにも入っていますboost::floyd_warshall_all_pairs_shortest_paths(graph, result);resultは「result[vertex1][vertex2] としたときに辺の重みが返る」ものなら何でもよい。例えばstd::map< vertex_descriptor,std::map<vertex_descriptor, int> > (辺の重みがintの場合)

沼ノ端追分

新得南千歳

白石

滝川旭川

富良野

岩見沢

Page 44: Boost.GraphでJR全線乗り尽くしプランを立てる - プログラミング生放送+CLR/H+Sapporo.cpp 勉強会@札幌 (2014.7.12)

4. (どこの辺を2本に増やすか決めたい)

次数が奇数の頂点を2つずつ組み合わせ、さっき求めた距離の和が最小になるものを見つける

沼ノ端追分

新得南千歳

白石

滝川旭川

富良野

岩見沢

●(白石, 旭川)・(南千歳, 新得)・(沼ノ端, 岩見沢)・(滝川, 富良野)

●(白石, 南千歳)・(沼ノ端, 岩見沢)・(滝川, 新得)・(旭川, 富良野)…

Page 45: Boost.GraphでJR全線乗り尽くしプランを立てる - プログラミング生放送+CLR/H+Sapporo.cpp 勉強会@札幌 (2014.7.12)

4. (どこの辺を2本に増やすか決めたい)

次数が奇数の頂点を2つずつ組み合わせ、さっき求めた距離の和が最小になるものを見つける

沼ノ端追分

新得南千歳

白石

滝川旭川

富良野

岩見沢

最適な組み合わせ:(白石, 岩見沢)・(南千歳, 沼ノ端)・(滝川, 旭川)・(富良野, 新得)

Page 46: Boost.GraphでJR全線乗り尽くしプランを立てる - プログラミング生放送+CLR/H+Sapporo.cpp 勉強会@札幌 (2014.7.12)

最適な「2つずつの組み合わせ方」を求めるのは面倒

●全通り組み合わせてみるのは、組み合わせ爆発を起こしてしまう

●「整数計画問題」という形に落とせば、ライブラリに食わせて解ける→今回は"GLPK"を使います

Page 47: Boost.GraphでJR全線乗り尽くしプランを立てる - プログラミング生放送+CLR/H+Sapporo.cpp 勉強会@札幌 (2014.7.12)

整数計画問題●変数に整数しか入らず、かつ指定された制約式を満たすものの中で特定の式を最大化/最小化する問題制約式・最大化/最小化する式には和・定数倍・等式/不等式のみ利用可能

●変数が多いと一般には低速(組み合わせ爆発が起きる)だが、多くの場合に高速

●今回の場合は、頂点数の3乗に比例する程度の時間で解ける(っぽい)

●GLPK:これを解いてくれるライブラリ

Page 48: Boost.GraphでJR全線乗り尽くしプランを立てる - プログラミング生放送+CLR/H+Sapporo.cpp 勉強会@札幌 (2014.7.12)

どう整数計画問題にするのか●変数:2つの駅の組み合わせ(使ったもの:1、使わなかったもの:0)

●制約式:どの駅も1回しか登場しない●最小化すべきもの:組み合わせにより生じる移動距離の総和

最小化すべき式:777×白石滝川+348×白石岩見沢+…// 「組の距離×使った辺」を最小にする。各組の距離はさっき求めた0≦白石滝川≦1、0≦白石岩見沢≦1、0≦白石沼ノ端≦1、…// 各組み合わせは「使うか使わないか」の二つだけ白石滝川+白石岩見沢+白石沼ノ端+…=1白石滝川+滝川岩見沢+滝川沼ノ端+…=1// 各駅とも、1回の組み合わせにしか登場しない

Page 49: Boost.GraphでJR全線乗り尽くしプランを立てる - プログラミング生放送+CLR/H+Sapporo.cpp 勉強会@札幌 (2014.7.12)

GLPKに解かせた結果(JR北海道分)

沼ノ端

追分

新得南千歳

白石

滝川旭川

富良野

岩見沢

Page 50: Boost.GraphでJR全線乗り尽くしプランを立てる - プログラミング生放送+CLR/H+Sapporo.cpp 勉強会@札幌 (2014.7.12)

GLPKに解かせた結果(JR全国分)

Page 51: Boost.GraphでJR全線乗り尽くしプランを立てる - プログラミング生放送+CLR/H+Sapporo.cpp 勉強会@札幌 (2014.7.12)

GLPKに解かせた結果(JR全国分)

メモリ不足で解けませんでした…。頂点数140くらい、考えるべき辺が10,000組くらい

Page 52: Boost.GraphでJR全線乗り尽くしプランを立てる - プログラミング生放送+CLR/H+Sapporo.cpp 勉強会@札幌 (2014.7.12)

最終結果:JR北海道全線(橋と、最小距離組み合わせの結果出た辺のみ2回通ればよい)

函館

五稜郭

中小国

大沼

長万部

室蘭東室蘭

苫小牧

沼ノ端追分

新得夕張新夕張

東釧路

根室南千歳

新千歳空港

桑園 白石

新十津川

増毛

滝川

深川

旭川 新旭川

稚内

富良野

様似

岩見沢

━━━━:2回通る━━━━:1回通る

JR北海道の総距離2457.7km(営業キロ)左図の総乗車距離3565.0km(同)総距離の145%

Page 53: Boost.GraphでJR全線乗り尽くしプランを立てる - プログラミング生放送+CLR/H+Sapporo.cpp 勉強会@札幌 (2014.7.12)

最終結果:JR北海道全線(橋と、最小距離組み合わせの結果出た辺のみ2回通ればよい)

函館

五稜郭

中小国

大沼

長万部

室蘭東室蘭

苫小牧

沼ノ端追分

新得夕張新夕張

東釧路

根室南千歳

新千歳空港

桑園 白石

新十津川

増毛

滝川

深川

旭川 新旭川

稚内

富良野

様似

岩見沢

一筆書き経路の例白石→桑園→新十津川→桑園→長万部→森→大沼→五稜郭→函館→五稜郭→中小国→五稜郭→大沼→森→長万部→東室蘭→室蘭→東室蘭→苫小牧→様似→苫小牧→沼ノ端→追分→岩見沢→白石→南千歳→沼ノ端→南千歳→新千歳空港→南千歳→追分→新夕張→夕張→新夕張→新得→東釧路→根室→東釧路→新旭川→稚内→新旭川→旭川→深川→増毛→深川→滝川→富良野→新得→富良野→旭川→深川→滝川→岩見沢→白石

Page 54: Boost.GraphでJR全線乗り尽くしプランを立てる - プログラミング生放送+CLR/H+Sapporo.cpp 勉強会@札幌 (2014.7.12)

補足:●「2回通る必要のある辺」が求められれば、

実際にどの経路で辿ればよいかは勝手に決まる。

●オイラーグラフの特徴として、「辿れなくなる頂点が存在しなくならない限りは、適当に辿っていても一筆書きになる」というものがあるため。

Page 55: Boost.GraphでJR全線乗り尽くしプランを立てる - プログラミング生放送+CLR/H+Sapporo.cpp 勉強会@札幌 (2014.7.12)

実際にプログラムで解いてみます

Page 56: Boost.GraphでJR全線乗り尽くしプランを立てる - プログラミング生放送+CLR/H+Sapporo.cpp 勉強会@札幌 (2014.7.12)

参考文献・資料:●アルゴリズムの大枠の解説:「経営科学OR用語大事典」Saul I. Gass、Carl M. Harris森村英典[監訳]、刀根薫[監訳]、伊理正夫[監訳]朝倉書店 ISBN 4254121318

●グラフ理論の基礎:「グラフ理論入門(原書第4版)」Robin J. Wilson、西関隆夫[訳]・西関裕子[訳]近代科学社 ISBN 4764902966参考資料:http://ocw.hokudai.ac.jp/Course/Faculty/Engineering/GraphTheory/2007/

Page 57: Boost.GraphでJR全線乗り尽くしプランを立てる - プログラミング生放送+CLR/H+Sapporo.cpp 勉強会@札幌 (2014.7.12)

参考文献・資料:●もっと難しい(理論的に考えたときに計算時間がかかる)問題:「JRの切符として買える最長のものを求める」(最長片道切符)http://www.swa.gr.jp/lop/

Page 58: Boost.GraphでJR全線乗り尽くしプランを立てる - プログラミング生放送+CLR/H+Sapporo.cpp 勉強会@札幌 (2014.7.12)

ありがとうございました