1. 説明
巡回セールスマン問題 (TSP) は、指定された一連の都市を訪れ、開始都市に戻る最短経路を見つけようとするよく知られた最適化問題です。
TSP は NP 困難 (非決定性多項式時間困難) 問題です。考えられるすべての入力を多項式時間で解決できる既知のアルゴリズムはありません。都市の数が増えると、可能なツアーの数が指数関数的に増加するため、大規模な問題の場合、最適な解決策を徹底的に探索することは計算上不可能です。
2. 解決策の議論
最適に近いソリューションを見つけるのに効果的なソリューションがいくつかあります。1 つの方法は、近似アルゴリズムを使用することです。これらのアルゴリズムは、最適に近いソリューションを提供しますが、必ずしも最適であるとは限りません。最適性を犠牲にして効率性を追求し、解をより速く計算できるようにします。よく知られている近似アルゴリズムは最近傍アルゴリズムです。
これは貪欲なアプローチです。欲張りな基準は、最も近い都市を選択することです。
最近傍アルゴリズムは、TSP のシンプルかつ直観的な近似です。任意の都市から開始し、すべての都市を訪問するまで、最も近い未訪問の都市を繰り返し選択します。
ドイツから 5 つの都市を選択してみましょう: ベルリン、ケルン、フランクフルト、ハンブルク、ミュンヘン。
# coordinates of cities
berlin = {"lat":52.5200, "lon": 13.4050}
hamburg = {"lat":53.5511, "lon": 9.9937}
munich = {"lat":48.1351, "lon": 11.5820}
cologne = {"lat":50.9375, "lon": 6.9603}
frankfurt = {"lat":50.1109, "lon": 8.6821}
cities = [berlin, hamburg, munich, cologne, frankfurt]
各都市間の差異を計算し、距離行列を完成させることができます。
import math
def calculate_distance(city1, city2):
"""distance between two cities"""
lat1, lon1 = city1["lat"], city1["lon"]
lat2, lon2 = city2["lat"], city2["lon"]
radius = 6371 # Radius of the Earth in kilometers
dlat = math.radians(lat2 - lat1)
dlon = math.radians(lon2 - lon1)
a = math.sin(dlat / 2) ** 2 + math.cos(math.radians(lat1)) * math.cos(math.radians(lat2)) * math.sin(dlon / 2) ** 2
c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a))
distance = radius * c
return distance
def get_distance_matrix(cities):
"""populate distance matrix"""
num_cities = len(cities)
distances = [[0] * num_cities for _ in range(num_cities)]
for i in range(num_cities):
for j in range(i + 1, num_cities):
dist = distance_between(cities[i], cities[j])
distances[i][j] = int(dist)
distances[j][i] = int(dist)
return distances
distances = get_distance_matrix(cities)
for row in distances:
print(row)
"""
[0, 255, 504, 477, 423]
[255, 0, 612, 356, 392]
[504, 612, 0, 456, 304]
[477, 356, 456, 0, 152]
[423, 392, 304, 152, 0]
"""
距離行列。
3. アルゴリズム
- 任意の都市を現在の都市として開始します。ベルリン
- 現在の都市を訪問済みとしてマークします。
- すべての都市を訪問するまで、次の手順を繰り返します。
1つ。最寄りの未訪問の都市を検索します。ハンバーガー
b. 最も近い未訪問の都市に移動します。
c. 最近訪問していない都市を訪問済みとしてマークします。
d. 現在の都市と最も近い未訪問の都市の間の距離をツアーの全長に追加します。
4. すべての都市を訪問した後、出発都市に戻ってツアーを完了します。
4.Pythonの実装
def solve_tsp_nearest(distances):
num_cities = len(distances)
visited = [False] * num_cities
tour = []
total_distance = 0
# Start at the first city
current_city = 0
tour.append(current_city)
visited[current_city] = True
# Repeat until all cities have been visited
while len(tour) < num_cities:
nearest_city = None
nearest_distance = math.inf
# Find the nearest unvisited city
for city in range(num_cities):
if not visited[city]:
distance = distances[current_city][city]
if distance < nearest_distance:
nearest_city = city
nearest_distance = distance
# Move to the nearest city
current_city = nearest_city
tour.append(current_city)
visited[current_city] = True
total_distance += nearest_distance
# Complete the tour by returning to the starting city
tour.append(0)
total_distance += distances[current_city][0]
return tour, total_distance
tour, total_distance = solve_tsp_nearest(distances)
print("Tour:", tour)
print("Total distance:", total_distance)
"""
Tour: [0, 1, 3, 4, 2, 0]
Total distance: 1571
"""
実際の地図上にプロットしてみましょう。
import folium
m = folium.Map(location=[52.52, 13.405], zoom_start=6)
cities = [(52.5200, 13.4050), (53.5511, 9.9937), (48.1351, 11.5820), (50.9375, 6.9603), (50.1109, 8.6821)]
for i in range(len(cities)):
folium.Marker(location=cities[i], tooltip=f"City {i}").add_to(m)
paths = [[0, 1], [0, 2], [0, 3], [0, 4], [1, 2], [1, 3], [1, 4], [2, 3], [2, 4], [3, 4]]
for path in paths:
start_city = cities[path[0]]
end_city = cities[path[1]]
folium.PolyLine(locations=[start_city, end_city], color='red').add_to(m)
min_cost_path = [0, 1, 3, 4, 2, 0]
for i in range(len(min_cost_path)-1):
start_city = cities[min_cost_path[i]]
end_city = cities[min_cost_path[i+1]]
folium.PolyLine(locations=[start_city, end_city], color='green').add_to(m)
地図上のTSP。画像は著者提供。
5. 追記
トラベラー問題はグラフ理論に基づいた問題であり、その目的は、パスが最小の合計重みですべてのノードを通過するようなパスを特定のグラフ内で見つけることです。この問題の解決策には、アリコロニーアルゴリズム、遺伝的アルゴリズム、貪欲アルゴリズムなどを使用できます。
このうちアリコロニーアルゴリズムは、アリの餌を求める行動をシミュレートして最適化問題を解くアルゴリズムです。アリは食べ物を探すときにフェロモンを放出して進路を示し、他のアリはそのフェロモンに基づいて進路を選択します。この動作をシミュレートすることにより、アリは特定のグラフ内で最適なパスを見つけることができます。
遺伝的アルゴリズムは、問題を解決するために生物学的進化のプロセスをシミュレートするアルゴリズムです。遺伝的アルゴリズムでは、初期集団の個体は、選択、交叉、突然変異などの操作を通じて、問題に対するより適切な解決策を徐々に進化させます。遺伝的アルゴリズムのパラメータと演算を適切に設定することにより、旅行者問題においてより良い解決策を得ることができます。
貪欲アルゴリズムは、局所的な最適解を使用して大域的な最適解を取得するアルゴリズムです。トラベラー問題では、貪欲な戦略を使用して、現在のノードに最も近い未訪問のノードを次のアクセス ポイントとして選択できます。貪欲アルゴリズムは必ずしも最適解が得られるわけではありませんが、計算速度が速く、実際にはより実用的な解を得ることができます。
上記の 3 つのアルゴリズムに加えて、動的計画法、深さ優先探索、分枝限定などのアルゴリズムもトラベラー問題を解決するために使用できます。使用する特定のアルゴリズムは、実際の問題の特性に基づいて選択する必要があります。オカン・イェニガン