特定のノードにアクセスするグラフで最短経路を見つけます


84

約100個のノードと約200個のエッジを持つ無向グラフがあります。1つのノードには「start」というラベルが付けられ、もう1つは「end」というラベルが付けられ、「mustpass」というラベルが付けられたノードが約12個あります。

'start'で始まり、 'end'で終わり、すべての 'mustpass'ノードを(任意の順序で)通過する、このグラフの最短パスを見つける必要があります

http://3e.org/local/maize-graph.png / http://3e.org/local/maize-graph.dot.txtは問題のグラフであり、ペンシルバニア州ランカスターのトウモロコシの迷路を表しています)

回答:


78

これを巡回セールスマン問題と比較している他の誰もがおそらくあなたの質問を注意深く読んでいません。TSPの目的は、すべての頂点を訪問する最短のサイクル(ハミルトン閉路)を見つけることです。これは、「mustpass」というラベルの付いたすべてのノードを持つことに対応します。

あなたの場合、「mustpass」というラベルの付いたラベルが約12個しかなく、12個あるとすると!はかなり小さい(479001600)ので、「mustpass」ノードのみのすべての順列を試して、「mustpass」ノードにこの順序でアクセスする「start」から「end」までの最短パスを調べることができます。そのリスト内の2つの連続するノードごとの最短パスを連結します。

言い換えると、最初に頂点の各ペア間の最短距離を見つけます(ダイクストラのアルゴリズムなどを使用できますが、それらの数が少ない(100ノード)場合、コード化が最も簡単なFloyd-Warshallアルゴリズムでも時間内に実行されます)。次に、これをテーブルに入れたら、「mustpass」ノードのすべての順列と残りを試してください。

このようなもの:

//Precomputation: Find all pairs shortest paths, e.g. using Floyd-Warshall
n = number of nodes
for i=1 to n: for j=1 to n: d[i][j]=INF
for k=1 to n:
    for i=1 to n:
        for j=1 to n:
            d[i][j] = min(d[i][j], d[i][k] + d[k][j])
//That *really* gives the shortest distance between every pair of nodes! :-)

//Now try all permutations
shortest = INF
for each permutation a[1],a[2],...a[k] of the 'mustpass' nodes:
    shortest = min(shortest, d['start'][a[1]]+d[a[1]][a[2]]+...+d[a[k]]['end'])
print shortest

(もちろん、これは実際のコードではありません。実際のパスが必要な場合は、どの順列が最短距離を与えるか、またすべてのペアの最短パスが何であるかを追跡する必要がありますが、アイデアは得られます。)

妥当な言語では最大で数秒で実行されます:)
[n個のノードとk'mustpass 'ノードがある場合、その実行時間はFloyd-Warshall部分ではO(n 3)、O(k!n )すべての順列部分について、100 ^ 3 +(12!)(100)は、実際に制限的な制約がない限り、実質的にピーナッツです。]


6
入力サイズが小さいことを考えると、私は答えに同意します。しかし、これがTSPの場合であるという他の人の主張を拒否する理由に興味があります。私の理解では、すべての必須ノードを抽出し、それを使用してサブグラフを作成できます。サブグラフのノード間のエッジには、元のグラフのAPSPソリューションに対応する重みがあります。それでは、質問はサブグラフのTSPのインスタンスになりませんか?あなたの解決策は、その問題に対する力ずくの解決策のようです(これは問題ありません)。
maditya 2013

7
@maditya:まず、(別の回答に対するSteven A Loweのコメントを引用すると)「TSPは難しい、bwahahaha」のような回答は、解決すべき実際の問題を抱えている人、特に非常に簡単な人にとっては適切な回答ではないことに同意してください。過去数十年のどのコンピューターでも解決しました。第二に、これは些細な理由(異なる入力形式)のためにTSPと同一ではありません。含まれるTSPの小さなインスタンスは、入力サイズNの1つではなく、より小さなグラフ用です。したがって、NP完全性は「必須」ノードの数に依存します。漸近的にあります。それは常に12、またはO(Nをログ)だ場合、それはNP完全などはありません
ShreevatsaR

1
結果がパスになるかどうかはわかりません。からac通過する必要があると想像してくださいb。からbへの最短パスがエッジac共有している可能性があります。その場合、エッジは2回繰り返されます。サイクルを生成しないためには、2つのパスのいずれかが最適よりも悪い必要があります。
Spak 2018年

1
@PietroSaccardi質問の説明から、目標は単にこれらすべてのノードを通過する最短の「方法」を見つけることであるように思われ、いくつかのエッジが繰り返されても問題ない場合があります。つまり、「パス」は緩い意味で使用されています。実際、エッジの繰り返しが許可されていない場合は、答えさえない可能性があります(たとえば、Bを通過するときにAからCに移動するように求められるグラフB-A-Cを考えてみてください。繰り返しない方法はありません。 B-エッジ)。
ShreevatsaR 2018年

Floyd-Warshallアルゴリズムは、ここでは正しく実装されていません。配列のすべてのセルがで初期化されるINFため、線はにd[i][j] = min(d[i][j], d[i][k] + d[k][j])なりd[i][j] = min(INF, INF + INF)、すべてのセルは常にに等しくなりINFます。この配列をグラフのエッジの長さで埋めるステップを追加する必要があります。
ステフ

25

ダイクストラのアルゴリズムを実行して、すべての重要なノード(開始、終了、および通過する必要がある)間の最短経路を見つけます。次に、深さ優先探索により、すべてのノードの開始に接触する結果のサブグラフを通る最短経路が示されます。 .mustpasses ...終了


これは、選択したソリューションよりも効率的である可能性があるようです。もしあなたがそれをもう少し肉付けしていたなら、それはより高い得点だっただろうに違いない。最初に、すべてのペア間の最短パスが、必要なすべてのノード間のパスを保証するかどうかを検討する必要がありました。しかし、そうなると思います(無向と仮定)。
galactikuh 2016年

パスがエッジを繰り返さないようにする必要がある場合、これは機能しないと思います。
tuket 2016

1
深さ優先探索は、コードの出現24日目の例で、どのようにして最短経路を見つけるのでしょうか。adventofcode.com/2016/day/24
Erwin Rooijakkers 2017

16

これは2つの問題です...スティーブン・ロウはこれを指摘しましたが、問題の後半について十分な敬意を払っていませんでした。

最初に、すべての重要なノード(start、end、mustpass)間の最短パスを見つける必要があります。これらのパスが検出されると、簡略化されたグラフを作成できます。新しいグラフの各エッジは、元のグラフの1つの重要なノードから別の重要なノードへのパスです。ここで最短パスを見つけるために使用できるパスファインディングアルゴリズムはたくさんあります。

ただし、この新しいグラフを作成すると、巡回セールスマン問題が発生します(まあ、ほとんど...開始点に戻る必要はありません)。上記のこれに関する投稿はすべて適用されます。


14

実際、あなたが投稿した問題は巡回セールスマンに似ていますが、単純な経路探索問題に近いと思います。すべてのノードにアクセスする必要はなく、特定のノードのセットに可能な限り短い時間(距離)でアクセスする必要があります。

この理由は、巡回セールスマン問題とは異なり、コーンメイズでは、他のノードを通過せずに、マップ上の任意の1つのポイントから他のポイントに直接移動することができないためです。

検討する手法として、実際にはA *パスファインディングをお勧めします。これを設定するには、どのノードが他のどのノードに直接アクセスできるか、および特定のノードからの各ホップの「コスト」を決定します。この場合、ノードの間隔が比較的狭いように見えるため、各「ホップ」のコストは同じであるように見えます。A *はこの情報を使用して、任意の2つのポイント間の最低コストパスを見つけることができます。ポイントAからポイントBに移動し、その間の約12を訪問する必要があるため、パスファインディングを使用した力ずくのアプローチでもまったく問題はありません。

検討するための単なる代替手段。それは巡回セールスマン問題のように非常によく見えます、そしてそれらは読むのに良い論文です、しかしよく見るとそれがただ過度に複雑なことであることがわかります。^ _ ^これは、以前にこの種のことを扱ったことがあるビデオゲームプログラマーの心から来ています。


2
+ 1-これは「巡回セールスマン問題は難しい、bwahahaha」よりもはるかに良い答えです
Steven A. Lowe

5

アンドリュートップは正しい考えを持っています:

1)ダイクストラのアルゴリズム2)いくつかのTSPヒューリスティック。

Lin-Kernighanヒューリスティックをお勧めします。これは、NP完全問題で最もよく知られているものの1つです。他に覚えておくべき唯一のことは、ステップ2の後でグラフを再度展開した後、展開されたパスにループがある可能性があるため、それらを短絡することを回避する必要があることです(パスに沿った頂点の程度を確認してください)。

私は実際、このソリューションが最適なソリューションと比較してどれほど優れているかわかりません。おそらく、短絡に関係するいくつかの病理学的症例があります。結局のところ、この問題はシュタイナー木によく似ています:http//en.wikipedia.org/wiki/Steiner_treeそして、グラフを縮小してクラスカル法を実行するだけでは、シュタイナー木を概算することはできません。


5

これはTSPの問題ではなく、NP困難でもありません。元の質問では、通過する必要のあるノードに1回だけアクセスする必要がないためです。これにより、ダイクストラのアルゴリズムを介してすべての必須パスノード間の最短パスのリストをコンパイルした後、ブルートフォース攻撃を行うだけで答えがはるかに簡単になります。より良い方法があるかもしれませんが、簡単な方法は、単純に二分木を逆方向に操作することです。ノードのリスト[start、a、b、c、end]を想像してみてください。単純な距離を合計します[開始-> a-> b-> c->終了]これは、ビートする新しいターゲット距離です。ここで[start-> a-> c-> b-> end]を試してみて、それがターゲットとして設定したほうがよい場合(そして、それがノードのパターンから来たことを思い出してください)。順列を逆方向に処理します。

  • [開始-> a-> b-> c->終了]
  • [開始-> a-> c-> b->終了]
  • [開始-> b-> a-> c->終了]
  • [開始-> b-> c-> a->終了]
  • [開始-> c-> a-> b->終了]
  • [開始-> c-> b-> a->終了]

それらの1つが最短になります。

(「複数回アクセスされた」ノードがある場合はどこにありますか?それらは最短パス初期化ステップで非表示になっています。aとbの間の最短パスにはcまたはエンドポイントが含まれる場合があります。気にする必要はありません。 )


最短経路であるという条件で、一度だけ訪問する必要があります。
Aziuth 2016年

ええと。私は1分前に​​かなり確信していましたが、ええ、あなたは正しいです。明らかに、いくつかの枝がある木ではありません。しかし、問題を抽象化して、完全に接続されたマストパスノードのみを含む新しいグラフに変換すると、ノードは元のグラフの最短パスの距離になり、TSPに到達します。それで、それがNP困難ではないと確信していますか?一般的な問題では、マストパスノードの数はノードの総数に依存すると思います。たとえば、合計がマストパスの多項式である場合、NP困難になりますね。
Aziuth 2016年

たとえば、a-> bからのルートはcを通過する場合があります。したがって、brnachが他を妨げることはありません。それは単なる順列です。
bjorke 2016年

はい?ただし、「合計ノードはマストパスノードの多項式である」のように、マストパスノードの数が合計ノードの数に何らかの関係があると仮定すると、順列はO(n!)になります。あなたは力ずくでTSPを解決しました。
Aziuth 2016年

2

ノードとエッジの数が比較的有限であることを考慮すると、おそらくすべての可能なパスを計算し、最短のパスを取ることができます。

一般に、これは巡回セールスマン問題として知られており、使用するアルゴリズムに関係なく、非決定論的な多項式ランタイムがあります。

http://en.wikipedia.org/wiki/Traveling_salesman_problem


1

質問は、任意の順序で合格する必要があることについて話します。通過しなければならないノードの定義された順序に関する解決策を探しています。私は自分の答えを見つけましたが、StackOverflowに同様の質問がなかったので、最大の人々がそれから利益を得ることができるようにここに投稿します。

順序または必須パスが定義されている場合は、ダイクストラのアルゴリズムを複数回実行できます。たとえば、sパススルーk1k2およびk3(それぞれの順序で)から開始し、で停止する必要があると仮定しますe。次に、ノードの連続する各ペア間でダイクストラのアルゴリズムを実行することができます。コストパスがで与えられることになります。

dijkstras(s, k1) + dijkstras(k1, k2) + dijkstras(k2, k3) + dijkstras(k3, 3)


0

ダースの「必見」ノードでブルートフォースを使用するのはどうですか。12ノードの可能なすべての組み合わせを簡単にカバーできます。これにより、それらをカバーするために従うことができる最適な回路が得られます。

これで、問題は、開始ノードから回路までの最適なルートを見つけることの1つに単純化されます。次に、それらをカバーするまでそれをたどり、そこから最後までのルートを見つけます。

最終パスは次のもので構成されます。

開始->回路へのパス*->ノードにアクセスする必要がある回路->終了へのパス*->終了

私が*でマークしたパスはこのように見つかります

開始ノードから回路上のすべてのポイントまでA *検索を実行し、これらのそれぞれについて、回路上の次のノードと前のノードから終了までA *検索を実行します(どちらの方向にも回路をたどることができるため)最終的には検索パスが多くなり、コストが最も低いものを選択できます。

検索をキャッシュすることで最適化の余地はたくさんありますが、これは良い解決策を生み出すと思います。

ただし、最適な解決策を探すことにはほど遠いです。それは、検索内で必見の回路を離れることを伴う可能性があるためです。


0

どこにも言及されていないことの1つは、同じ頂点がパス内で複数回アクセスされても問題ないかどうかです。ここでの回答のほとんどは、同じエッジに複数回アクセスすることは問題ないことを前提としていますが、質問(パスは同じ頂点に複数回アクセスするべきではありません!)を考えると、同じ頂点に2回アクセスすることはできません

したがって、ブルートフォースアプローチは引き続き適用されますが、パスの各サブセットを計算しようとするときに、すでに使用されている頂点を削除する必要があります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.