• ベストアンサー
※ ChatGPTを利用し、要約された質問です(原文:巡回セールスマン問題の考え方を使って・・・。)

巡回セールスマン問題の考え方を使って最短経路を求める方法について教えてください

このQ&Aのポイント
  • 巡回セールスマン問題の考え方を使って、対象地の14の交差点を最短経路で一筆書きする方法について教えてください。
  • プログラムを改良して、スタートが交差点1でゴールが交差点14の場合の最短経路と距離を表示する方法について教えてください。
  • 建築の学生ですが、卒論の対象地の分析に巡回セールスマン問題の考え方を使いたいです。どのようにプログラムを変更すればよいか教えてください。

質問者が選んだベストアンサー

  • ベストアンサー
  • stomachman
  • ベストアンサー率57% (1014/1775)
回答No.12

No.11訂正です。名前がだぶっちゃってますね。 > routeに沿った各交差点間の距離の表示をしたいのなら、routeのたとえば > 右隣に20行1列のエリア"road"を作り、関数putResultの末尾に > With Range("road") この"road"は全部別の名前、例えば"length"に訂正!! (ひとりで10回以上回答してしまった。アホですね。)

nintai
質問者

お礼

stomachmanさん本当にありがとうございました。 卒論の作業でお礼をするのが遅くなってしまいました。

その他の回答 (11)

  • stomachman
  • ベストアンサー率57% (1014/1775)
回答No.11

No.147691の回答No.4のプログラムで説明した通りです。それにあと、"start"という名前のcellと、"goal"という名前のcellを追加。 つまり points,minDistance,start,goalはそれぞれ1個のcell、 route はたとえば20行1列のエリア、 roadはたとえば20行20列の正方形のエリア です。 routeに沿った各交差点間の距離の表示をしたいのなら、routeのたとえば右隣に20行1列のエリア"road"を作り、関数putResultの末尾に With Range("road") For k = 1 To nPoint - 1 .Cells(k, 1) = dist(minRoute(k-1),minRoute(k)) Next k End With を追加しておけば良い。

  • stomachman
  • ベストアンサー率57% (1014/1775)
回答No.10

>点はすべて観光スポットです ということで構わないのであれば、ま、宜しいでしょう。  本気でやれば、距離じゃなく所要時間、それも時間帯によって変化する、など非常に複雑な問題になっちゃいますね。    何にせよ、意図を正確に表現なさることは、建築・都市計画など、「ひとりじゃ何もできない」分野では特に重要かと…いや、これは余計なお節介でした。  細かい事ながら、No.8のPrivate Sub search(i, distance, move, pregoals)の中の ElseIf minDistance > distance + dist(i, j) + minLast Then は ElseIf pregoals1 > 0 And minDistance > distance + dist(i, j) + minLast Then にした方がちょびっと速い。

nintai
質問者

お礼

おっしゃるとおりです。実際、先生には大変迷惑かけてる学生です。 組んでもらったプログラムではExcelのシート上で B18 message (終了のメッセージを表示させる) B19   points(交差点数) B20   start (出発点をいれる) B21   minDistance (最小距離) B23~O23 route(ルートが表示される)  B2 ~O15 road (距離の行列表) というようにセルに名前をつけてました。 stomachmanさんにつくっていただいたプログラムの場合はどのように名前をつければいいいのでしょうか? そこのところが、すいませんよくわかりませんでした。

  • stomachman
  • ベストアンサー率57% (1014/1775)
回答No.9

No.7のコメントを見て、まだ、正しく問題が定義されていないらしいことがわかりました。はじめっから、何やりたいか仰っていただけば良かったのですが… ●点には2種類あります。観光地と通過点です。観光地は全部、丁度1度づつ通りたい。通過点は何度通っても良いし、1度も通らないものがあってもよい。  道は何度通っても良いし、一度も通らないものがあっても良い。なお、2つの点を結ぶ道が2つ以上ある場合には短い方だけを使えばよいので、長い方は初めから除いておきます。 こういう条件じゃないでしょうか。だとすると、またしてもNo.8のアルゴリズムは落第ということになりますが…

nintai
質問者

お礼

本当にありがとうございます。 ご指摘されましたが、 点はすべて観光スポットです、つまりそれら14地点はちょうど1度づつ通り、 2度通ってはいけない。という条件です。 「何度も通ってもよい点」はありません。 図で説明したいのですが、できないようなのでこれで私の意図はつたわったでしょうか?

  • stomachman
  • ベストアンサー率57% (1014/1775)
回答No.8

Dim nPoint As Integer Dim dist(20, 20) Dim route(100) As Integer Dim minRoute(100) As Integer Dim visit(20) As Boolean Dim minMove As Integer Dim minDistance, minLast Dim startPoint, goalPoint Dim initialMinDistance Dim pregoalpoints Sub check() getRoad Range("minDistance").ClearContents 'just for fun Range("route").ClearContents 'just for fun showMinDistance 'just for fun For j = 1 To nPoint visit(j) = False Next j route(0) = startPoint route(nPoint - 1) = goalPoint visit(startPoint) = True visit(goalPoint) = True Call search(startPoint, 0, 0, pregoalpoints) Call putResult End Sub Private Sub search(i, distance, move, pregoals) For jj = i To i + nPoint - 2 j = (jj Mod nPoint) + 1 If (Not visit(j)) And (dist(i, j) > 0) Then route(move + 1) = j visit(j) = True pregoals1 = pregoals If dist(j, goalPoint) > 0 Then pregoals1 = pregoals - 1 If pregoals1 = 0 And move = nPoint - 3 Then newDistance = distance + dist(i, j) + dist(j, goal) If minDistance > newDistance Then minDistance = newDistance showMinDistance 'just for fun For k = 0 To nPoint - 1 minRoute(k) = route(k) Next k End If ElseIf minDistance > distance + dist(i, j) + minLast Then Call search(j, distance + dist(i, j), move + 1, pregoals1) End If visit(j) = False End If Next jj End Sub Private Sub showMinDistance() Range("minDistance") = minDistance End Sub Private Sub putResult() If minDistance = initialMinDistance Then Range("route").Cells(1, 1) = "Not Found" Exit Sub End If showMinDistance With Range("route") For k = 0 To nPoint - 1 .Cells(k + 1, 1) = minRoute(k) Next k End With End Sub Private Sub getRoad() startPoint = Range("start").Value goalPoint = Range("goal").Value nPoint = Range("points").Value With Range("road") For i = 1 To nPoint For j = 1 To nPoint dist(i, j) = .Cells(i, j).Value Next j dist(i, i) = 0 Next i End With minDistance = 0 For i = 1 To nPoint For j = 1 To nPoint minDistance = minDistance + dist(i, j) Next j Next i pregoalpoints = 0 minLast = minDistance For j = 1 To nPoint If dist(j, goalPoint) > 0 Then pregoalpoints = pregoalpoints + 1 If minLast > dist(j, goalPoint) Then minLast = dist(j, goalPoint) End If Next j If dist(startPoint, goalPoint) > 0 Then pregoalpoints = pregoalpoints - 1 initialMinDistance = minDistance End Sub 出発点に戻るround tripをやりたい場合には、出発点のコピー(つまり出発点から繋がっている全て交差点Xと、出発点とXの距離と同じ距離で繋がっている交差点)を新たに付け加え、これを到着点として実行すれば良いのです。

  • stomachman
  • ベストアンサー率57% (1014/1775)
回答No.7

えと。ご質問の正確な意味を確認したいと思います。 (1) 交差点同士を道で繋いだ地図がある。道にはそれぞれ「距離」が対応づけられている。 (2) 交差点のうち、出発点sと到着点g(s≠g)が指定されている。 (3) sからgへの経路であって、全ての交差点を丁度1度づつ通る経路のうちで、最短距離であるものを求めるアルゴリズムは? こういうご質問ですか? だとすれば、ここまでの回答は全部間違いです。  普通、一筆書きといいますと、 (1)どの道も一度しか通ってはならない。そして (2)全ての道を通らねばならない。 そういう経路を求めよ、という意味ですぜ。(同じ交差点を何度通っても良いんですよ。 ∞ という図形を一筆書きしろと言われたら、交差点をどうしても2度通るでしょ?)  ご質問の場合「最短距離」を求めようというのですから、上記の2条件のうち(2)は外して考えるしかないと解釈いたしました結果が、これまでの回答です。全部はずれ。  という訳で、はじめからやりなおしです。もうちょっと待ってね。

nintai
質問者

お礼

stomachmanさん。こんなに丁寧に付き合ってくれて本当にありがとうございます。 まさにご指摘とおりです。 私の説明が本当に不十分ですいませんでした。 一筆書きが同じ交差点を何度通ってもいいとは知りませんでした。そうです。私の意図は、同じ交差点は二度通ってはいけないという条件下における経路探索です。 というのも観光ルート的なものを提案するのが目的なので。 待ちます。よろしくお願いします。

  • stomachman
  • ベストアンサー率57% (1014/1775)
回答No.6

No.5を前提として。 No.147691の回答No.4のプログラムにおいて、worksheetに"start"という名前のcellと、"goal"という名前のcellを追加し、そこに出発点とゴールの交差点の番号を入力して、実行。 今度は一応テストしましたよ。 Dim nPoint As Integer Dim dist(20, 20) Dim available(20, 20) As Boolean Dim move As Integer Dim route(100) As Integer Dim minRoute(100) As Integer Dim visit(20) As Integer Dim minMove As Integer Dim minDistance Dim startPoint, goalPoint Dim initialMinDistance Sub check() getRoad clearAvailable Range("minDistance").ClearContents 'just for fun Range("route").ClearContents 'just for fun showMinDistance 'just for fun For j = 1 To nPoint visit(j) = 0 Next j route(0) = startPoint visit(startPoint) = visit(startPoint) + 1 Call search(startPoint, 0, 0) Call putResult End Sub Private Sub search(i, distance, move) For jj = i To i + nPoint - 2 j = (jj Mod nPoint) + 1 goon = available(i, j) And (dist(i, j) > 0) ' If goon Then ' If visit(i) > 1 And move > 0 Then ' goon = (route(move - 1) <> j) ' End If ' End If If goon Then available(i, j) = False: available(j, i) = False route(move + 1) = j visit(j) = visit(j) + 1 If minDistance > distance + dist(i, j) Then If roundTrip(move + 1) Then minDistance = distance + dist(i, j) showMinDistance 'just for fun minMove = move + 1 For k = 0 To minMove minRoute(k) = route(k) Next k Else Call search(j, distance + dist(i, j), move + 1) End If End If available(i, j) = True: available(j, i) = True visit(j) = visit(j) - 1 End If Next jj End Sub Private Sub showMinDistance() Range("minDistance") = minDistance End Sub Private Sub putResult() If minDistance = initialMinDistance Then Range("route").Cells(1, 1) = "Not Found" Exit Sub End If showMinDistance With Range("route") For k = 0 To minMove .Cells(k + 1, 1) = minRoute(k) Next k .Cells(minMove + 2, 1) = "" End With End Sub Private Function roundTrip(m) rountTrip = False If m < nPoint Then Exit Function If route(m) <> goalPoint Then Exit Function For kk = 1 To nPoint If visit(kk) = 0 Then Exit Function Next kk roundTrip = True End Function Private Sub getRoad() startPoint = Range("start").Value goalPoint = Range("goal").Value minDistance = 0 nPoint = Range("points").Value With Range("road") For i = 1 To nPoint For j = 1 To nPoint dist(i, j) = .Cells(i, j).Value minDistance = minDistance + dist(i, j) Next j Next i End With initialMinDistance = minDistance End Sub Private Sub clearAvailable() For i = 1 To nPoint For j = 1 To nPoint available(i, j) = (dist(i, j) > 0) Next j Next i End Sub

nintai
質問者

お礼

「一筆書き」と書いたのですが、ニュアンスが伝わっていなかったでしょうか? まさに指摘されたとおり「同じ交差点に2度来ちゃいけない」という条件で す。組んでもらったプログラムはそうなっているはずです。 また僕のパソコンが遅いのかわかりませんが、交差点数が14になると大変時間がかかるようです。 stomachman さんはどれくらいで終わるのでしょうか?

  • stomachman
  • ベストアンサー率57% (1014/1775)
回答No.5

ひょっとして、 「同じ交差点に2度来ちゃいけない」なんて条件がついてたりは、まさかしませんよね。それだとまた話が違うので。

nintai
質問者

お礼

ありがとうございます。 「一筆書き」と書いたのですが、ニュアンスが伝わっていなかったでしょうか? まさに指摘されたとおり「同じ交差点に2度来ちゃいけない」という条件で す。組んでもらったプログラムはそうなっているはずです。 テストまでしていただいたのに大変申し訳ないのですが・・

  • stomachman
  • ベストアンサー率57% (1014/1775)
回答No.4

おっとと、見落とし。 今度の問題では、スタートとゴールも指定するのでした。単に最短経路を求めるのではなく、他の全部の交差点も通過しなくちゃいけなくて、しかも一度通った道は通らない。こういう条件ですね。 めんどくさいから、一応テストした上でまるごとupします。ちょっと待っててね。

  • stomachman
  • ベストアンサー率57% (1014/1775)
回答No.3

文法エラーのことですか。だったら、 Range("route")と .Cells(1, 1)の間にスペースが挟まっているせいです。スペースを消せば良いはず。

  • stomachman
  • ベストアンサー率57% (1014/1775)
回答No.2

交差点を通る一筆書きでしたか。使わない道があっても良いのですね。 だとすれば、「片道を通ると、その帰り道も使えなくなる」という条件を入れてやるだけです。 つまり、No.147691の回答No.4のプログラムを少し手直しするだけです。 まず関数Private Sub search(i, distance, move) の中で available(i, j) = False となっている部分を available(i, j) = False : available(j,i) = False に、変え、また available(i, j) = True となっている部分を available(i, j) = True : available(j,i) = True に変えます。 それからね、解がない場合があり得ますから、プログラムの先頭に グローバル変数 Dim intialMinDistance を付け加え、関数Private Sub getRoad() の最後に intialMinDistance=minDistance End Sub として、初期値を記録しておきます。そうして、Private Sub putResult() において、最初に if minDistance = initialMinDistance then Range("route") .Cells(1, 1) = "Not Found" exit sub end if を追加して、解が無かったことを表示させます。 あとは一緒。No.147691より探索はずっと早く終わるでしょう。 今回はテストしてません。

nintai
質問者

お礼

いつも本当にありがとうございます。 以下のところでエラーが出ます。 Range("route") .Cells(1, 1) = "Not Found" 特におかしな事はした覚えがないのですが。 身近な人にも聞いてますが、もしも原因にお気づきになったら教えてくれると大変うれしいのですが・・ ありがとうございます。

関連するQ&A

専門家に質問してみよう