algorithm
Podróżujący sprzedawca
Szukaj…
Uwagi
Problemem wędrownego sprzedawcy jest problem znalezienia minimalnego kosztu podróży przez N wierzchołków dokładnie raz na wierzchołek. Koszt przejazdu z wierzchołka i do wierzchołka j jest cost[i][j] .
Istnieją 2 rodzaje algorytmów, które rozwiązują ten problem: dokładne algorytmy i algorytmy aproksymacyjne
Dokładne algorytmy
- Algorytm Brute Force
- Algorytm programowania dynamicznego
Algorytmy aproksymacyjne
Do dodania
Algorytm Brute Force
Ścieżka przez każdy wierzchołek dokładnie raz jest taka sama, jak uporządkowanie wierzchołka w jakiś sposób. Tak więc, aby dokładnie obliczyć minimalny koszt podróży przez każdy wierzchołek, możemy brutalnie użyć siły każdego z N! permutacje liczb od 1 do N
Psuedocode
minimum = INF
for all permutations P
current = 0
for i from 0 to N-2
current = current + cost[P[i]][P[i+1]] <- Add the cost of going from 1 vertex to the next
current = current + cost[P[N-1]][P[0]] <- Add the cost of going from last vertex to the first
if current < minimum <- Update minimum if necessary
minimum = current
output minimum
Złożoność czasu
Jest N! przejść przez permutacje, a koszt każdej ścieżki jest obliczany w O(N) , dlatego ten algorytm potrzebuje O(N * N!) czasu na podanie dokładnej odpowiedzi.
Algorytm programowania dynamicznego
Zauważ, że jeśli weźmiemy pod uwagę ścieżkę (w kolejności):
(1,2,3,4,6,0,5,7)
i ścieżka
(1,2,3,5,0,6,7,4)
Koszt przejścia od wierzchołka 1 do wierzchołka 2 do wierzchołka 3 pozostaje taki sam, więc dlaczego trzeba go ponownie obliczyć? Ten wynik można zapisać do późniejszego wykorzystania.
Niech dp[bitmask][vertex] reprezentuje minimalny koszt podróży przez wszystkie wierzchołki, których odpowiadający bit w bitmask jest ustawiony na 1 kończący się na vertex . Na przykład:
dp[12][2]
12 = 1 1 0 0
^ ^
vertices: 3 2 1 0
Ponieważ 12 oznacza 1100 , dp[12][2] oznacza przechodzenie przez wierzchołki 2 i 3 na wykresie ze ścieżką kończącą się na wierzchołku 2.
Zatem możemy mieć następujący algorytm (implementacja C ++):
int cost[N][N]; //Adjust the value of N if needed
int memo[1 << N][N]; //Set everything here to -1
int TSP(int bitmask, int pos){
int cost = INF;
if (bitmask == ((1 << N) - 1)){ //All vertices have been explored
return cost[pos][0]; //Cost to go back
}
if (memo[bitmask][pos] != -1){ //If this has already been computed
return memo[bitmask][pos]; //Just return the value, no need to recompute
}
for (int i = 0; i < N; ++i){ //For every vertex
if ((bitmask & (1 << i)) == 0){ //If the vertex has not been visited
cost = min(cost,TSP(bitmask | (1 << i) , i) + cost[pos][i]); //Visit the vertex
}
}
memo[bitmask][pos] = cost; //Save the result
return cost;
}
//Call TSP(1,0)
Ta linia może być trochę myląca, więc przejdźmy ją powoli:
cost = min(cost,TSP(bitmask | (1 << i) , i) + cost[pos][i]);
Tutaj, bitmask | (1 << i) ustawia i-ty bit bitmask na 1, co oznacza, że i-ty wierzchołek został odwiedzony. i po przecinku reprezentuje nowe pos w tym wywołania funkcji, która reprezentuje nową „ostatni” wierzchołek. cost[pos][i] to suma kosztu podróży z wierzchołka pos do wierzchołka i .
Zatem wiersz ten ma zaktualizować wartość cost do minimalnej możliwej wartości podróży do każdego innego wierzchołka, który nie był jeszcze odwiedzany.
Złożoność czasu
Funkcja TSP(bitmask,pos) ma 2^N wartości dla bitmask i N wartości dla pos . Każda funkcja potrzebuje czasu O(N) do uruchomienia (pętla for ). Tak więc implementacja zajmuje czas O(N^2 * 2^N) aby uzyskać dokładną odpowiedź.