Spaces:
Sleeping
Sleeping
import streamlit as st | |
import folium | |
from geopy.geocoders import Nominatim | |
from geopy.distance import geodesic | |
from itertools import combinations | |
import numpy as np | |
import polyline | |
import requests | |
# Algoritma Held-Karp untuk TSP | |
def held_karp_tsp(dist_matrix): | |
n = len(dist_matrix) | |
inf = float('inf') | |
memo = {} | |
# Initialize memo table for subsets of size 2 | |
for i in range(1, n): | |
memo[(1 << i, i)] = dist_matrix[0][i] | |
# Fill memo table for larger subsets | |
for subset_size in range(2, n): | |
for subset in combinations(range(1, n), subset_size): | |
bits = 0 | |
for bit in subset: | |
bits |= 1 << bit | |
for next_city in subset: | |
prev_bits = bits & ~(1 << next_city) | |
min_dist = inf | |
for k in subset: | |
if k == next_city: | |
continue | |
current_dist = memo[(prev_bits, k)] + dist_matrix[k][next_city] | |
if current_dist < min_dist: | |
min_dist = current_dist | |
memo[(bits, next_city)] = min_dist | |
# Find optimal tour | |
bits = (2 ** n - 1) - 1 | |
min_tour_cost = inf | |
last_city = None | |
for k in range(1, n): | |
tour_cost = memo[(bits, k)] + dist_matrix[k][0] | |
if tour_cost < min_tour_cost: | |
min_tour_cost = tour_cost | |
last_city = k | |
# Backtrack to find the full tour | |
tour = [0] | |
bits = (2 ** n - 1) - 1 | |
for _ in range(n - 1): | |
tour.append(last_city) | |
bits &= ~(1 << last_city) | |
next_city = min( | |
[(memo[(bits, k)] + dist_matrix[k][last_city], k) for k in range(n) if (bits, k) in memo], | |
key=lambda x: x[0], | |
)[1] | |
last_city = next_city | |
tour.append(0) | |
return min_tour_cost, tour | |
# Mendapatkan koordinat kota dari nama | |
def get_coordinates(city_name): | |
geolocator = Nominatim(user_agent="tsp_app") | |
location = geolocator.geocode(city_name) | |
if location: | |
return (location.latitude, location.longitude) | |
else: | |
return None | |
# Menghitung jarak antar semua pasangan kota | |
def create_distance_matrix(coordinates): | |
n = len(coordinates) | |
dist_matrix = np.zeros((n, n)) | |
for i in range(n): | |
for j in range(i + 1, n): | |
dist_matrix[i][j] = geodesic(coordinates[i], coordinates[j]).kilometers | |
dist_matrix[j][i] = dist_matrix[i][j] | |
return dist_matrix | |
# Fungsi untuk menampilkan peta rute | |
def plot_route(map_obj, coordinates, route): | |
for i in range(len(route) - 1): | |
start = coordinates[route[i]] | |
end = coordinates[route[i + 1]] | |
folium.Marker(location=start, tooltip=f'City {route[i] + 1}').add_to(map_obj) | |
folium.Marker(location=end, tooltip=f'City {route[i + 1] + 1}').add_to(map_obj) | |
folium.PolyLine([start, end], color="blue", weight=2.5, opacity=1).add_to(map_obj) | |
# Add markers for start and end points | |
folium.Marker(location=coordinates[0], tooltip='Start', icon=folium.Icon(color="green")).add_to(map_obj) | |
folium.Marker(location=coordinates[route[-2]], tooltip='End', icon=folium.Icon(color="red")).add_to(map_obj) | |
return map_obj | |
# Streamlit UI | |
st.title("Traveling Salesman Problem Solver") | |
# Input kota | |
city_names = st.text_input("Masukkan nama kota (pisahkan dengan koma)", "Jakarta, Bandung, Surabaya, Yogyakarta") | |
city_list = [city.strip() for city in city_names.split(",")] | |
if len(city_list) < 2: | |
st.warning("Masukkan setidaknya dua kota.") | |
else: | |
coordinates = [get_coordinates(city) for city in city_list] | |
if None in coordinates: | |
st.error("Ada kota yang tidak ditemukan. Pastikan nama kota benar.") | |
else: | |
# Buat distance matrix | |
dist_matrix = create_distance_matrix(coordinates) | |
min_cost, optimal_route = held_karp_tsp(dist_matrix) | |
# Tampilkan hasil | |
st.write(f"Biaya total minimum: {min_cost:.2f} km") | |
st.write("Rute optimal:", " -> ".join([city_list[i] for i in optimal_route])) | |
# Buat peta | |
map_obj = folium.Map(location=coordinates[0], zoom_start=5) | |
plot_route(map_obj, coordinates, optimal_route) | |
# Render map | |
st_folium = st.components.v1.html(folium.Map._repr_html_(map_obj), width=700, height=500) |