Reisende selgerproblem: Python, C++ Algoritme
โก Smart oppsummering
Det reisende selgerproblemet er en klassisk NP-hard optimaliseringsoppgave som ber om den korteste turen som besรธker hver by nรธyaktig รฉn gang og returnerer til opprinnelsesstedet, ved hjelp av avstandsdata levert gjennom en graf.

Hva er Traveling Salesman Problem (TSP)?
Den reisende selgerproblemet (TSP) er et klassisk kombinatorisk optimaliseringsproblem innen teoretisk informatikk. Gitt en graf av byer, spรธr TSP etter den korteste veien som besรธker hver node nรธyaktig รฉn gang og returnerer til opprinnelsesbyen.
Problemstillingen gir en liste over byer sammen med avstandene mellom hvert bypar.
Mรฅlet: Start i startbyen, besรธk hver annen by nรธyaktig รฉn gang, og returner til startbyen. Mรฅlet er รฅ finne den korteste mulige tur-retur-ruten.
Eksempel pรฅ TSP
Se pรฅ grafen nedenfor, hvor 1, 2, 3 og 4 representerer byene, og vekten pรฅ hver kant representerer avstanden mellom disse byene.
Mรฅlet er รฅ finne den kortest mulige turen som starter fra opprinnelsesbyen, besรธker alle andre byer nรธyaktig รฉn gang, og returnerer til opprinnelsesbyen.
For grafen ovenfor er den optimale ruten 1-2-4-3-1Den korteste turkostnaden er 10 + 25 + 30 + 15 = 80.
Forskjellige lรธsninger pรฅ reisende selgerproblem
Problemet med den reisende selgeren er klassifisert som NP-vanskelig fordi ingen kjent polynomisk tidsalgoritme lรธser det eksakt. Kompleksiteten vokser eksponentielt med antall byer.
Det finnes flere mรฅter รฅ angripe TSP pรฅ. De vanligste tilnรฆrmingene er:
Brute Force-tilnรฆrming: Den naive metoden beregner alle mulige turer og sammenligner dem. Antall turer i en graf med n byer er n!, noe som gjรธr brute force beregningsmessig svรฆrt dyrt for alt utover omtrent ti byer.
Gren- og bundet metode: Problemet er delt inn i delproblemer, og lรธsningene pรฅ disse delproblemene kombineres til en optimal lรธsning. Effektiv beskjรฆring forkaster delvise turer som ikke kan slรฅ dagens beste kostnad.
Denne veiledningen demonstrerer dynamisk programmeringstilnรฆrming, som er den memobaserte versjonen av branch og bound, og samsvarer med Bellman-Held-Karp-algoritmen.
Dynamisk programmering: Dette er en eksakt metode som sรธker den optimale lรธsningen ved รฅ gjenbruke overlappingping resultater for delproblemer. Det er tregere enn det nesten optimale grรฅdige metoder, men det gir alltid en globalt optimal tur.
Beregningskompleksiteten til denne tilnรฆrmingen er O(Nยฒ ร 2^N), som vi diskuterer senere i artikkelen.
Nรฆrmeste nabo-metode: En heuristisk, grรฅdig tilnรฆrming som alltid hopper til nรฆrmeste ubesรธkte by. Den er mye billigere enn dynamisk programmering, men garanterer ikke en optimal tur, sรฅ den brukes til nesten optimale lรธsninger nรฅr hastighet er viktigere enn eksakte minima.
Algoritme for reisende selgerproblem
Vi bruker den dynamiske programmeringsmetoden for รฅ lรธse TSP. Fรธr vi starter algoritmen, la oss avklare noen terminologier:
- En graf
G = (V, E)er et sett med hjรธrner og kanter. Ver settet med hjรธrner.Eer settet med kanter.- Topppunkter er forbundet gjennom kanter.
Dist(i, j)betegner den ikke-negative avstanden mellom hjรธrnene i og j.
Anta at S er en delmengde av byer trukket fra {1, 2, 3, โฆ, n} hvor i og j er to byer i den delmengden. Da cost(i, S, j) er lengden pรฅ den korteste ruten som starter ved i, besรธker hver by i S nรธyaktig รฉn gang, og slutter ved j.
For eksempel, cost(1, {2, 3, 4}, 1) angir den korteste veien der:
- Startby er 1
- Byene 2, 3 og 4 besรธkes bare รฉn gang
- Sluttpunktet er 1
Den dynamiske programmeringsrepetansen er:
- Sett
cost(i, {}, i) = 0, som betyr at vi starter og slutter pรฅ i med null kostnad. - Nรฅr
|S| > 1, definerecost(i, S, 1) = โforumi โ 1, fordi den faktiske turkostnaden er ukjent ennรฅ. - Start med by 1, velg den neste byen slik at
cost(i, S, j) = min [ cost(i, S โ {i}, j) + dist(i, j) ]forumi โ Sogi โ j.
For grafen ovenfor er adjacensmatrisen fรธlgende:
| dist(i, j) | 1 | 2 | 3 | 4 |
|---|---|---|---|---|
| 1 | 0 | 10 | 15 | 20 |
| 2 | 10 | 0 | 35 | 25 |
| 3 | 15 | 35 | 0 | 30 |
| 4 | 20 | 25 | 30 | 0 |
Slik gรฅr algoritmen frem:
Trinn 1) Reisen starter i by 1, besรธker alle andre byer รฉn gang og gรฅr tilbake til by 1.
Trinn 2) S er en delmengde av byer. For hver |S| > 1, initialiser cost(i, S, 1) = โ. Her cost(i, S, j) betegner en tur som starter ved i, besรธker byene i S รฉn gang og nรฅr j. Vi starter fra uendelig fordi avstanden er ukjent pรฅ dette punktet. Sรฅ verdiene er:
cost(2, {3, 4}, 1) = โ betyr at vi starter i by 2, gรฅr gjennom by 3 og 4, og nรฅr 1, med ukjent kostnad. Pรฅ samme mรฅte:
cost(3, {2, 4}, 1) = โ
cost(4, {2, 3}, 1) = โ
Trinn 3) For hver delmengde av S, beregn:
cost(i, S, j) = min [ cost(i, S โ {i}, j) + dist(i, j) ], Hvor j โ S og i โ j.
Det er den billigste turen som starter ved i, besรธker delmengden av byer รฉn gang og returnerer til j. Fordi turen starter ved by 1, er den optimale kostnaden cost(1, {other cities}, 1).
Arbeide med gjentakelsen trinn for trinn
Nรฅ er S = {1, 2, 3, 4}. Det er fire elementer, sรฅ antallet delmengder er 2^4 = 16Disse delmengdene er:
1) |S| = 0: {ฮฆ}
2) |S| = 1: {{1}, {2}, {3}, {4}}
3) |S| = 2: {{1, 2}, {1, 3}, {1, 4}, {2, 3}, {2, 4}, {3, 4}}
4) |S| = 3: {{1, 2, 3}, {1, 2, 4}, {2, 3, 4}, {1, 3, 4}}
5) |S| = 4: {{1, 2, 3, 4}}
Fordi turen starter i by 1, kan vi forkaste alle delmengder som inneholder by 1 mens vi beregner mellomliggende kostnader.
Algoritmeberegningen utfolder seg som fรธlger:
1) |S| = ฮฆ:
- kostnad(2, ฮฆ, 1) = ford(2, 1) = 10
- kostnad(3, ฮฆ, 1) = ford(3, 1) = 15
- kostnad(4, ฮฆ, 1) = ford(4, 1) = 20
2) |S| = 1:
- kostnad(2, {3}, 1) = dist(2, 3) + kostnad(3, ฮฆ, 1) = 35 + 15 = 50
- kostnad(2, {4}, 1) = dist(2, 4) + kostnad(4, ฮฆ, 1) = 25 + 20 = 45
- kostnad(3, {2}, 1) = dist(3, 2) + kostnad(2, ฮฆ, 1) = 35 + 10 = 45
- kostnad(3, {4}, 1) = dist(3, 4) + kostnad(4, ฮฆ, 1) = 30 + 20 = 50
- kostnad(4, {2}, 1) = dist(4, 2) + kostnad(2, ฮฆ, 1) = 25 + 10 = 35
- kostnad(4, {3}, 1) = dist(4, 3) + kostnad(3, ฮฆ, 1) = 30 + 15 = 45
3) |S| = 2:
- kostnad(2, {3, 4}, 1) = min [ dist(2, 3) + kostnad(3, {4}, 1) = 35 + 50 = 85, dist(2, 4) + kostnad(4, {3}, 1) = 25 + 45 = 70 ] = 70
- kostnad(3, {2, 4}, 1) = min [ dist(3, 2) + kostnad(2, {4}, 1) = 35 + 45 = 80, dist(3, 4) + kostnad(4, {2}, 1) = 30 + 35 = 65 ] = 65
- kostnad(4, {2, 3}, 1) = min [ dist(4, 2) + kostnad(2, {3}, 1) = 25 + 50 = 75, dist(4, 3) + kostnad(3, {2}, 1) = 30 + 45 = 75 ] = 75
4) |S| = 3:
- kostnad(1, {2, 3, 4}, 1) = min [ dist(1, 2) + kostnad(2, {3, 4}, 1) = 10 + 70 = 80, dist(1, 3) + kostnad(3, {2, 4}, 1) = 15 + 65 = 80, dist(1, 4) + kostnad(4, {2, 3}, 1) = 20 + 75 = 95 ] = 80
Sรฅ den optimale lรธsningen er 1-2-4-3-1.
Pseudokode
Algorithm: Traveling-Salesman-Problem
Cost (1, {}, 1) = 0
for s = 2 to n do
for all subsets S belongs to {1, 2, 3, ..., n} of size s
Cost (s, S, 1) = Infinity
for all i in S and i != 1
Cost (i, S, j) = min {Cost (i, S - {i}, j) + dist(i, j) for j in S and i != j}
Return min(i) Cost (i, {1, 2, 3, ..., n}, j) + d(j, i)
Implementering i C/C++
Her er implementeringen i C++Versjonen nedenfor fikser kildekoden sin tidlige return feilen, som kom tilbake etter den aller fรธrste permutasjonen i stedet for รฅ liste opp alle turene.
#include <bits/stdc++.h> using namespace std; #define V 4 #define MAX 1000000 int tsp(int graph[][V], int s) { vector<int> vertex; for (int i = 0; i < V; i++) if (i != s) vertex.push_back(i); int min_cost = MAX; do { int current_cost = 0; int j = s; for (int i = 0; i < vertex.size(); i++) { current_cost += graph[j][vertex[i]]; j = vertex[i]; } current_cost += graph[j][s]; min_cost = min(min_cost, current_cost); } while (next_permutation(vertex.begin(), vertex.end())); return min_cost; } int main() { int graph[][V] = { { 0, 10, 15, 20 }, { 10, 0, 35, 25 }, { 15, 35, 0, 30 }, { 20, 25, 30, 0 } }; int s = 0; cout << tsp(graph, s) << endl; return 0; }
Utgang:
80
Gjennomfรธring i Python
Ocuco Python implementeringen speiler C++ versjon. Den korrigerer kildens from itertools, import komma-skrivefeil, feilplassert return inne i den indre lรธkken, og det spredte innrykket pรฅ s = 0.
from sys import maxsize from itertools import permutations V = 4 def tsp(graph, s): vertex = [] for i in range(V): if i != s: vertex.append(i) min_cost = maxsize for perm in permutations(vertex): current_cost = 0 k = s for j in perm: current_cost += graph[k][j] k = j current_cost += graph[k][s] min_cost = min(min_cost, current_cost) return min_cost graph = [[0, 10, 15, 20], [10, 0, 35, 25], [15, 35, 0, 30], [20, 25, 30, 0]] s = 0 print(tsp(graph, s))
Utgang:
80
Akademiske lรธsninger til TSP
Dataforskere har brukt flere tiรฅr pรฅ รฅ lete etter forbedrede polynomtidsalgoritmer for den reisende selgerproblemet. Sรฅ langt er TSP fortsatt NP-hard.
Flere publiserte teknikker reduserer den praktiske kompleksiteten for spesifikke familier av TSP-forekomster:
- Den klassiske symmetriske TSP-en lรธses av Null suffiks metode.
- Ocuco Biogeografibasert optimaliseringsalgoritme bruker migreringsstrategier for รฅ lรธse optimaliseringsproblemer som er kartlagt til TSP.
- Ocuco Multi-objektiv evolusjonรฆr algoritme er designet for flermรฅls-TSP og bygger pรฅ NSGA-II.
- Ocuco Multiagentsystem Tilnรฆrmingen lรธser TSP for N byer med faste beregningsressurser.
- Ocuco Lin-Kernighan heuristisk og dens etterfรธlger LKH levere turer innenfor 2โ3 % av det optimale for tilfeller med millioner av byer.
- Concord bruker skjรฆreplan og forgrening-og-kutt for รฅ beregne eksakte optima for referanseforekomster med titusenvis av byer.
Anvendelse av Traveling Salesman Problem
Problemet med den reisende selgeren dukker opp i den virkelige verden i bรฅde ren og modifisert form. Noen av de viktigste anvendelsene er:
- Planlegging, logistikk og mikrochipproduksjon: Problemer med brikkeinnsetting i mikrobrikkeindustrien modelleres som TSP-varianter for รฅ minimere robotarmens reisetid.
- DNA-sekvensering: En modifisert TSP brukes i DNA-sekvensering der byer representerer DNA-fragmenter og avstander representerer likhet mellom fragmenter.
- Astronomi: Astronomer bruker TSP for รฅ minimere tiden brukt pรฅ รฅ dreie teleskoper mellom observasjonsmรฅl.
- Optimal kontroll: TSP-formuleringer modellerer optimale kontrollproblemer der flere begrensninger mรฅ overholdes samtidig som traverseringskostnadene minimeres.
- Siste mil levering: Amazon, UPS og matleveringsapper lรธser dynamiske TSP-varianter for รฅ sekvensere stopp for sjรฅfรธrer.
- Lagerplukking: Robotiske og menneskelige plukkere fรธlger TSP-optimaliserte ruter som forkorter reisetiden inne i distribusjonssentre.
Kompleksitetsanalyse av TSP
- Tidskompleksitet: Held-Karps dynamiske programmeringsmetod lรธser 2N delsett for hver startnode, noe som gir
N ร 2^Ndelproblemer. Hvert delproblem tar lineรฆr tid รฅ kombinere. Hvis opprinnelsesnoden er uspesifisert, kreves en ytre lรธkke over N noder. Den totale tidskompleksiteten erO(Nยฒ ร 2^N). - Romkompleksitet: DP-tabellen lagrer
C(S, i)for hvert delsett S av toppunktsettet. Det er 2N delmengder per node, sรฅ romkompleksiteten erO(N ร 2^N), som ofte skrives somO(2^N)nรฅr N behandles som fast.
Lรฆr deretter om Sil av Eratosthenes-algoritmen.




