私は、巡回セールスマン問題を解決するA *アルゴリズム(ヒューリスティックが提供されています)の実装を作成するように依頼されました。私はアルゴリズムを理解しています、それは十分に単純です、しかし私はそれを実装するコードを見ることができません。つまり、わかりました。距離+ヒューリスティック(ノード)でソートされたノードの優先キューは、パスに最も近いノードを追加します。問題は、たとえば、前の最も近いノードから最も近いノードに到達できない場合はどうなるかということです。関数の引数として実際に「グラフ」をどのように取るのでしょうか。アルゴリズムが実際にどのように機能するかをコードとして見ることができません。
質問を投稿する前にウィキペディアのページを読みました。繰り返し。それは実際には質問に答えません-グラフを検索することは、TSPを解決することとはまったく異なる方法です。たとえば、同じ長さの2つのパスが等しくないため、任意の時点で最短のノードが常にバックトラックになるグラフを作成できますが、AからBに移動しようとしている場合は、2つのパスがあります。同じ長さのものは等しい。
常に最初に最も近くに行くことによって、いくつかのノードに決して到達しないグラフを導き出すことができます。
A *がTSPにどのように適用されるかはよくわかりません。つまり、AからBへのルートを見つけることは確かです。しかし、TSP?接続が表示されません。
私は解決策を見つけました ここ
ヒューリスティックとして最小スパニングツリーを使用します。
初期状態の設定:開始都市のエージェントで、他の都市を訪問したことがない
目標の状態:エージェントはすべての都市を訪問し、再び開始都市に到達しました
後継機能:まだ訪問していないすべての都市を生成します
エッジコスト:ノードによって表される都市間の距離。このコストを使用してg(n)を計算します。
h(n):現在の都市から最も近い未訪問の都市までの距離+すべての未訪問の都市を移動するための推定距離(ここではMSTヒューリスティックを使用)+未訪問の都市から開始都市までの最も近い距離。これは許容可能なヒューリスティック関数であることに注意してください。計算を容易にするために、訪問した都市のリストと未訪問の都市のリストを維持することを検討できます。
アルゴリズムとその仕組みを理解するだけの問題である場合は、紙にグラフを描画し、それに重みを割り当てて描画することを検討することをお勧めします。また、おそらくダイクストラの最短経路を示すいくつかのアニメーションを見つけることができます ウィキペディア 良いものがあります。ダイクストラとA *の唯一の違いは、ヒューリスティックの追加であり、ターゲットノードに到達するとすぐに検索を停止します。 TSPを解決するためにそれを使用する限り、それで頑張ってください!
ここでの混乱は、TSPを解決しようとしているグラフがnotグラフであるということですでA *検索を実行しています。
関連項目を参照してください: 数独解法アルゴリズムC++
この問題を解決するには、次のことを行う必要があります。
私が考えることができる簡単な例:
これについてもう少し抽象的に考えてください。ちょっとA *を忘れてください、とにかくヒューリスティックなダイクストラです。以前、あなたはAからBに行きたいと思っていました。あなたの目標は何でしたか? Bに到達すること。目標は、最小のコストでBに到達することでした。ある時点で、あなたの現在の「状態」は何でしたか?おそらくグラフ上のあなたの場所だけです。
ここで、Aから始めて、BとCの両方に進みます。今の目標は何ですか。最小のコストを維持しながら、BとCの両方を通過させる。これは、D、E、F、...またはNノードだけで一般化できます。さて、ある時点で、あなたの現在の「状態」は何ですか?これは重要です。グラフ内の現在地だけでなく、BまたはCのどちらか、または検索でこれまでにアクセスしたノードでもあります。
Xを動かした後、「目標状態」に到達したかどうかを尋ねる関数を呼び出すように、元のアルゴリズムを実装します。以前は、関数は「はい、状態Bにいるので、目標にいます」と言っていました。しかし今、検索のパスが関心のある各ポイントを通過した場合、その関数が「はい、あなたはゴール状態にいます」を返すようにします。現在の状態に含まれているため、検索がすべての関心のあるポイントを通過したかどうかがわかります。
それを取得したら、ヒューリスティックで検索を改善し、A *します。
問題は、たとえば、前の最も近いノードから最も近いノードに到達できない場合はどうなるかということです。
この手順は必要ありません。のように、前の最も近いものから現在の最も近いものまでのパスを計算しておらず、ゴールノードに到達しようとしています。重要なのは現在の最も近いものだけです(たとえば、アルゴリズムはその最後の反復を気にしません)この反復では96kmしか離れていないため、100km離れていました)。
大まかな紹介として、A *はパスを直接構築しません。パスが探索した領域内に含まれていることが確実にわかるまで探索し、探索中に記録された情報に基づいてパスを構築します。
(説明を助けるためのリファレンス実装として ウィキペディアの記事のコード を使用します。)
closedset
とopenset
の2つのノードセットがあります。
closedset
は、完全に評価されたノードを保持します。つまり、ノードがstart
からどれだけ離れているかを正確に把握しており、すべての隣接ノードが2つのセットのいずれかにあります。これは、それらを使用して実行できる計算がこれ以上ないため、(一種の)無視することができます。 (基本的に、これらは完全に境界内に含まれています。)
openset
は「境界」ノードを保持します。これらがstart
からどれだけ離れているかはわかりますが、まだ隣接ノードに触れていないため、これまでのところ検索のエッジにあります。
(暗黙的に、3番目のセットがあります:完全に変更されていないノード。ただし、openset
に入るまで実際には触れないので、問題ありません。)
特定の反復で、探索するノード(つまり、openset
内のノード)がある場合は、探索するノードを特定する必要があります。これはヒューリスティックの仕事です。基本的に、goal
への最短パスがあると思われるノードを指定することにより、境界上のどのポイントを次に探索するのが最適かについてのヒントを提供します。
以前の最も近いノードは関係ありません。境界を少し拡大し、openset
に新しいノードを追加しました。これらの新しいノードは、この反復で最も近いノードの候補になります。
最初は、openset
にはstart
しか含まれていませんが、繰り返して、最終的にgoal
に到達するまで、各ステップで境界線を少し(最も有望な方向に)拡張します。 。
A *が実際に探索を行っているときは、どのノードがどこから来たのかを気にする必要はありません。 start
からの距離とヒューリスティック関数を知っているので、そうする必要はありません。必要なのはそれだけです。
ただし、後でパスを再構築するには、パスの記録が必要です。これがcamefrom
です。特定のノードについて、camefrom
はそれをstart
に最も近いノードにリンクするため、goal
から逆方向にリンクをたどることで最短パスを再構築できます。
関数の引数として実際に「グラフ」をどのように取るのでしょうか。
グラフの表現 のいずれかを渡すことによって。
A *がTSPにどのように適用されるかはよくわかりません。つまり、AからBへのルートを見つけることは確かです。しかし、TSP?接続が表示されません。
別のヒューリスティックと別の終了条件が必要です。goal
はもはや単一ノードではなく、すべてが接続されている状態です。ヒューリスティックは、残りのノードを接続する最短パスの長さの見積もりです。
あなたの質問の1つに答えるために...
グラフを関数の引数として渡すには、いくつかのオプションがあります。すべてのノードを含む配列へのポインターを渡すことができます。完全に接続されたグラフの場合は、開始ノードを1つだけ渡して、そこから作業することができます。そして最後に、必要なデータ構造を含むグラフクラスを記述し、そのクラスのインスタンスへの参照を渡すことができます。
最も近いノードに関する他の質問については、必要に応じてバックトラックするA *検索の一部ではありませんか?または、そのような状況を処理するために、独自の種類のバックトラックを実装することもできます。