巡回セールスマン問題を最近傍法で解く

巡回セールスマン問題を最近傍法で解いてみることにします。やり方は以下のとおり。

始点となる都市を適当に1つ選ぶ。これが今いる都市。
今までに訪れたことのない都市のうち、今いる都市に最も近い都市を訪れる
すべての都市を訪れるまで、これを繰り返す

このアルゴリズムはある程度良い解が出力されることが期待される方法ではありますが、解の精度はまったく保証されません。

都市の座標を管理するためのNodeクラスを定義します。

最近傍法で巡回セールスマン問題を解くクラスを定義します。

実際に都市の座標を適当に設定して処理をおこなわせてみます。

前回の動的計画法を使った場合よりも処理速度は速いです。都市の数が5000件あっても1~2秒で終わります。ただ正確な値を得られていません。

(参考)【paizaラーニング】最近傍法によるTSP

巡回セールスマン問題を貪欲法で解く

巡回セールスマン問題を貪欲法で解いてみることにします。やり方は以下のとおり。

各都市同士の距離を計算して近い順に連結する。
ただし
 ふたつ以上の都市と連結させない。
 閉路ができないようにする。
これによって全都市は一本のパスでつながることになる。最後に始点と終点を繋いげば巡回路が得られる

最初に都市の座標を管理するためのNodeクラスを定義します。

都市を近い順に連結していくのですが、3つ以上の都市が連結されたり閉路ができないようにしなければなりません。フィールド変数 ConnectCountは自分と連結している都市の数が格納されます。

閉路ができないようにするためには都市を連結するときに片方を親にします。親をもつ都市同士を連結するときは双方の親を比較します。親が同じだと閉路ができてしまうことになります。親が異なる場合は連結させるとともに、片方の親がもう片方の親の子になります。

Edgeクラスのコンストラクタの引数は異なる2つの都市です。コンストラクタ内で距離を計算してフィールド変数に格納します。

Joinメソッドはすでにふたつ以上の都市が連結しているときや、都市の親が同じ場合はなにもしません。それ以外のときは連結します。連結する場合はConnectCountをインクリメントするとともに片方の都市の親をもう片方の親の子にセットします。

上記のアルゴリズムで最短経路を求めるためのクラスを定義します。戻り値は最短経路で第二引数が最短距離を受け取る変数です。

実際に都市の座標を適当に設定して処理をおこなわせてみます。

最近傍法と比べると処理時間がかかります。ただし動的計画法を使った場合よりも処理速度は速いです。都市の数が3000件でも3秒近くかかります。また得られるのは正確な値ではありません。

(参考)【paizaラーニング】貪欲法によるTSP