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

  1. Algorytm Brute Force
  2. 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ź.



Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow