Travelling Salesman -ongelma: Python, C++ algoritmi
โก รlykรคs yhteenveto
Kauppamatkustajan ongelma on klassinen NP-vaikea optimointitehtรคvรค, jossa etsitรครคn lyhintรค kiertotietรค, joka kรคy jokaisessa kaupungissa tรคsmรคlleen kerran ja palaa lรคhtรถpisteeseen. Tehtรคvรคssรค kรคytetรครคn graafin kautta annettua etรคisyysdataa.

Mikรค on Travelling Salesman -ongelma (TSP)?
Kauppakamerongelma (TSP) on klassinen kombinatorinen optimointiongelma teoreettisessa tietojenkรคsittelytieteessรค. Kun kaupunkien verkko on annettu, TSP kysyy lyhintรค polkua, joka kรคy jokaisessa solmussa tรคsmรคlleen kerran ja palaa lรคhtรถkaupunkiin.
Ongelmankuvauksessa on luettelo kaupungeista sekรค niiden vรคlisistรค etรคisyyksistรค.
Tavoite: Aloita lรคhtรถkaupungista, vieraile jokaisessa muussa kaupungissa tasan kerran ja palaa lรคhtรถkaupunkiin. Tavoitteena on lรถytรครค lyhin mahdollinen edestakainen reitti.
Esimerkki TSP:stรค
Tarkastellaan alla olevaa kaaviota, jossa 1, 2, 3 ja 4 edustavat kaupunkeja ja jokaisen reunan paino edustaa etรคisyyttรค nรคiden kaupunkien vรคlillรค.
Tavoitteena on lรถytรครค lyhin mahdollinen matka, joka alkaa lรคhtรถkaupungista, kรคy jokaisessa muussa kaupungissa tasan kerran ja palaa lรคhtรถkaupunkiin.
Yllรค olevassa kaaviossa optimaalinen reitti on 1-2-4-3-1Lyhimmรคn matkan hinta on 10 + 25 + 30 + 15 = 80.
Erilaisia โโratkaisuja matkustavan myyjรคn ongelmaan
Kauppamatkustajan ongelma luokitellaan NP-vaikeaksi, koska mikรครคn tunnettu polynomiaikainen algoritmi ei ratkaise sitรค tarkasti. Monimutkaisuus kasvaa eksponentiaalisesti kaupunkien mรครคrรคn myรถtรค.
TSP:tรค voi hyรถkรคtรค monella eri tavalla. Yleisimmรคt lรคhestymistavat ovat:
Raa'an voiman lรคhestymistapa: Naiivi menetelmรค laskee kaikki mahdolliset kierrokset ja vertaa niitรค. Kierrosten lukumรครคrรค graafissa, jossa on n kaupunkia, on n!, mikรค tekee raa'an voiman laskennallisesti erittรคin kalliiksi yli kymmenen kaupungin osalta.
Haara- ja sidontamenetelmรค: Ongelma jaetaan osaongelmiin, ja nรคiden osaongelmien ratkaisut yhdistetรครคn optimaaliseksi ratkaisuksi. Tehokas karsinta hylkรครค osittaiset matkat, jotka eivรคt pysty parantamaan nykyistรค parasta kustannustehokkuutta.
Tรคmรค opetusohjelma havainnollistaa dynaaminen ohjelmointimenetelmรค, joka on branch- ja bound-lausekkeiden ulkoa tallennettava versio ja vastaa Bellman-Held-Karp-algoritmia.
Dynaaminen ohjelmointi: Tรคmรค on tarkka menetelmรค, joka etsii optimaalista ratkaisua kรคyttรคmรคllรค uudelleen pรครคllekkรคisyyttรคping osaongelman tuloksia. Se on hitaampaa kuin lรคhes optimaalinen ahneita menetelmiรค, mutta se palauttaa aina globaalisti optimaalisen kierroksen.
Tรคmรคn lรคhestymistavan laskennallinen monimutkaisuus on O(Nยฒ ร 2^N), jota kรคsittelemme myรถhemmin artikkelissa.
Lรคhimmรคn naapurin menetelmรค: Heuristinen ahne lรคhestymistapa, joka hyppรครค aina lรคhimpรครคn vierailemattomaan kaupunkiin. Se on paljon halvempi kuin dynaaminen ohjelmointi, mutta ei takaa optimaalista kierrosta, joten sitรค kรคytetรครคn lรคhes optimaalisiin ratkaisuihin, kun nopeus on tรคrkeรคmpรครค kuin tarkat minimit.
Algoritmi matkustavan myyjรคn ongelmalle
Kรคytรคmme dynaamista ohjelmointia TSP:n ratkaisemiseen. Ennen algoritmin aloittamista selvitetรครคn muutamia terminologiaa:
- Kaavio
G = (V, E)on joukko solmuja ja reunoja. Von joukko kรคrkipisteitรค.Eon reunojen joukko.- Vertices yhdistetรครคn reunojen kautta.
Dist(i, j)tarkoittaa pisteiden i ja j vรคlistรค ei-negatiivista etรคisyyttรค.
Oletetaan, ettรค S on joukko kaupunkeja, jotka on johdettu joukosta {1, 2, 3, โฆ, n}, missรค i ja j ovat kaksi kaupunkia tรคssรค joukossa. Silloin cost(i, S, j) on lyhimmรคn reitin pituus, joka alkaa pisteestรค i, kรคy jokaisessa S:n kaupungissa tรคsmรคlleen kerran ja pรครคttyy pisteeseen j.
Esimerkiksi cost(1, {2, 3, 4}, 1) tarkoittaa lyhintรค polkua, jossa:
- Aloituskaupunki on 1
- Kaupungeissa 2, 3 ja 4 kรคydรครคn vain kerran
- Loppupiste on 1
Dynaamisen ohjelmoinnin rekursio on:
- Asettaa
cost(i, {}, i) = 0, mikรค tarkoittaa, ettรค aloitamme ja lopetamme i:hen nollakustannuksella. - Kun
|S| > 1, mรครคrittelecost(i, S, 1) = โvarteni โ 1koska matkan todellinen hinta ei ole vielรค tiedossa. - Aloita kaupungista 1 ja valitse seuraava kaupunki niin, ettรค
cost(i, S, j) = min [ cost(i, S โ {i}, j) + dist(i, j) ]varteni โ Sjai โ j.
Yllรค olevassa kaaviossa vierekkรคisyysmatriisi on seuraava:
| 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 |
Nรคin algoritmi etenee:
Vaihe 1) Matka alkaa kaupungista 1, vierailee kerran jokaisessa muussa kaupungissa ja palaa kaupunkiin 1.
Vaihe 2) S on kaupunkien osajoukko. Jokaisella |S| > 1, alusta cost(i, S, 1) = โ. Tรคssรค cost(i, S, j) tarkoittaa kiertomatkaa, joka alkaa pisteestรค i, vierailee kerran S:n kaupungeissa ja saapuu pisteeseen j. Lรคhdemme liikkeelle รครคrettรถmyydestรค, koska etรคisyys on tรคssรค pisteessรค tuntematon. Joten arvot ovat:
cost(2, {3, 4}, 1) = โ tarkoittaa, ettรค aloitamme kaupungista 2, kuljemme kaupunkien 3 ja 4 lรคpi ja saavutamme kaupungin 1, mutta kustannukset ovat tuntemattomat. Samoin:
cost(3, {2, 4}, 1) = โ
cost(4, {2, 3}, 1) = โ
Vaihe 3) Laske jokaiselle S:n osajoukolle:
cost(i, S, j) = min [ cost(i, S โ {i}, j) + dist(i, j) ], Jossa j โ S ja i โ j.
Se on pienimmรคn kustannuksen omaava kiertomatka, joka alkaa kaupungista i, vierailee kerran joukon kaupunkeja sisรคltรคvรคssรค joukossa ja palaa kaupunkiin j. Koska kiertomatka alkaa kaupungista 1, optimaalinen kustannus on cost(1, {other cities}, 1).
Toistumisen kรคsittely vaihe vaiheelta
Nyt S = {1, 2, 3, 4}. Alkioita on neljรค, joten osajoukkojen lukumรครคrรค on 2^4 = 16Nuo osajoukot ovat:
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}}
Koska kierros alkaa kaupungista 1, voimme hylรคtรค kaikki kaupungin 1 sisรคltรคvรคt osajoukot laskiessamme vรคlikustannuksia.
Algoritmin laskenta etenee seuraavasti:
1) |S| = ฮฆ:
- kustannus(2, ฮฆ, 1) = jakauma(2, 1) = 10
- kustannus(3, ฮฆ, 1) = jakauma(3, 1) = 15
- kustannus(4, ฮฆ, 1) = jakauma(4, 1) = 20
2) |S| = 1:
- kustannus(2, {3}, 1) = dist(2, 3) + kustannus(3, ฮฆ, 1) = 35 + 15 = 50
- kustannus(2, {4}, 1) = dist(2, 4) + kustannus(4, ฮฆ, 1) = 25 + 20 = 45
- kustannus(3, {2}, 1) = dist(3, 2) + kustannus(2, ฮฆ, 1) = 35 + 10 = 45
- kustannus(3, {4}, 1) = dist(3, 4) + kustannus(4, ฮฆ, 1) = 30 + 20 = 50
- kustannus(4, {2}, 1) = dist(4, 2) + kustannus(2, ฮฆ, 1) = 25 + 10 = 35
- kustannus(4, {3}, 1) = dist(4, 3) + kustannus(3, ฮฆ, 1) = 30 + 15 = 45
3) |S| = 2:
- kustannus(2, {3, 4}, 1) = min [ dist(2, 3) + kustannus(3, {4}, 1) = 35 + 50 = 85, dist(2, 4) + kustannus(4, {3}, 1) = 25 + 45 = 70 ] = 70
- kustannus(3, {2, 4}, 1) = min [ dist(3, 2) + kustannus(2, {4}, 1) = 35 + 45 = 80, dist(3, 4) + kustannus(4, {2}, 1) = 30 + 35 = 65 ] = 65
- kustannus(4, {2, 3}, 1) = min [ dist(4, 2) + kustannus(2, {3}, 1) = 25 + 50 = 75, dist(4, 3) + kustannus(3, {2}, 1) = 30 + 45 = 75 ] = 75
4) |S| = 3:
- kustannus(1, {2, 3, 4}, 1) = min [ dist(1, 2) + kustannus(2, {3, 4}, 1) = 10 + 70 = 80, dist(1, 3) + kustannus(3, {2, 4}, 1) = 15 + 65 = 80, dist(1, 4) + kustannus(4, {2, 3}, 1) = 20 + 75 = 95 ] = 80
Joten optimaalinen ratkaisu on 1-2-4-3-1.
Pseudokoodi
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)
Toteutus C/C++
Tรคssรค on toteutus C++Alla oleva versio korjaa lรคhteen varhaisen return bugi, joka palasi aivan ensimmรคisen permutaation jรคlkeen kaikkien kierrosten luetteloinnin sijaan.
#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; }
lรคhtรถ:
80
Toteutus sisรครคn Python
Python toteutus heijastelee C++ versio. Se korjaa lรคhteen from itertools, import pilkku kirjoitusvirhe, vรครคrin sijoitettu return sisemmรคn silmukan sisรคllรค ja harhaileva sisennys pรครคllรค 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))
lรคhtรถ:
80
Akateemiset ratkaisut TSP:lle
Tietojenkรคsittelytieteilijรคt ovat vuosikymmeniรค etsineet parempia polynomiaikaisia โโalgoritmeja kauppamatkustajan ongelmaan. Toistaiseksi kauppamatkustajan ongelma on edelleen NP-vaikea.
Useat julkaistut tekniikat vรคhentรคvรคt kรคytรคnnรถn monimutkaisuutta tietyille TSP-instanssiryhmille:
- Klassinen symmetrinen kokonaispistepotenssi ratkaistaan โโseuraavasti: Nollaliitemenetelmรค.
- Biogeografiaan perustuva optimointialgoritmi kรคyttรครค migraatiostrategioita TSP:hen liittyvien optimointiongelmien ratkaisemiseen.
- Monitavoitteinen evoluutioalgoritmi on suunniteltu monitavoitteista TSP:tรค varten ja perustuu NSGA-II:een.
- Moniagenttijรคrjestelmรค lรคhestymistapa ratkaisee TSP:n N kaupungille kiinteillรค laskentaresursseilla.
- Lin-Kernighanin heuristiikka ja sen seuraaja LKH toimittaa matkoja, jotka ovat 2โ3 prosentin sisรคllรค optimaalisesta miljoonien kaupunkien tapauksissa.
- Concorde kรคyttรครค leikkaustasoja ja haarautumis-ja-leikkaus-menetelmรครค laskeakseen tarkat optimaaliset arvot kymmenien tuhansien kaupunkien vertailuinstansseille.
Travelling Salesman -ongelman soveltaminen
Kauppamatkustajan ongelma esiintyy tosielรคmรคssรค sekรค puhtaassa ettรค muunnellussa muodossa. Joitakin tรคrkeimpiรค sovelluksia ovat:
- Suunnittelu, logistiikka ja mikrosirujen valmistus: Mikrosiruteollisuudessa sirun asettamiseen liittyviรค ongelmia mallinnetaan TSP-variantteina robottikรคsivarren liike-ajan minimoimiseksi.
- DNA-sekvensointi: Modifioitua TSP:tรค kรคytetรครคn DNA-sekvensoinnissa, jossa kaupungit edustavat DNA-fragmentteja ja etรคisyydet edustavat fragmenttien vรคlistรค samankaltaisuutta.
- Tรคhtitiede: Tรคhtitieteilijรคt kรคyttรคvรคt TSP:tรค minimoidakseen teleskooppien siirtรคmiseen kรคytetyn ajan havaintokohteiden vรคlillรค.
- Optimaalinen hallinta: TSP-formulaatiot mallintavat optimaalisen hallinnan ongelmia, joissa on otettava huomioon useita rajoitteita samalla minimoiden lรคpikulkukustannukset.
- Viimeisen kilometrin toimitus: Amazon, UPS ja ruokalรคhettisovellukset ratkaisevat dynaamiset TSP-variantit kuljettajien pysรคhdysten jรคrjestรคmiseksi.
- Varastokerรคily: Robotti- ja ihmiskerรคilijรคt seuraavat TSP:n optimoimia reittejรค, jotka lyhentรคvรคt matka-aikaa jakelukeskuksissa.
TSP:n monimutkaisuusanalyysi
- Ajan monimutkaisuus: Held-Karpin dynaaminen ohjelmointimenetelmรค ratkaisee 2N osajoukot kullekin aloitussolmulle, jolloin saadaan
N ร 2^Naliongelmia. Jokaisen aliongelman yhdistรคminen vie lineaarisen ajan. Jos lรคhtรถsolmua ei ole mรครคritelty, tarvitaan ulompi silmukka N solmun yli. Kokonaisaikakompleksisuus onO(Nยฒ ร 2^N). - Avaruuden monimutkaisuus: DP-pรถytรค tallentaa
C(S, i)jokaiselle solmujoukon osajoukolle S. On olemassa 2N osajoukkoja solmua kohden, joten avaruuskompleksisuus onO(N ร 2^N), joka usein kirjoitetaan muodossaO(2^N)kun N:รครค kรคsitellรครคn kiinteรคnรค.
Seuraavaksi tutustu Eratosthenes-algoritmin seula.




