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.

  • ๐Ÿ—บ๏ธ Ongelmailmoitus: Kun on annettu painotettu kaupunkien ja parittaisten etรคisyyksien kuvaaja, etsi pienimmรคn kustannuksen Hamiltonin sykli, joka alkaa ja pรครคttyy samaan lรคhtรถkaupunkiin.
  • โš™๏ธ Ratkaisuperheet: Raaka voima luetteloi kaikki n! kierrosta, haarautuva ja rajautuva luumuhaku, dynaaminen ohjelmointi tallentaa vรคlimuistiin aliongelmat ja lรคhimmรคn naapurin haku tarjoaa nopean heuristiikan.
  • ๐Ÿ“‰ Dynaaminen ohjelmointi: Held-Karpin rekursiokustannus(i, S, j) kรคyttรครค uudelleen lyhyimpiรค polkuja solmujen osajoukkojen lรคpi ja antaa tarkan O(Nยฒ ยท 2^N) aikaratkaisun.
  • ๐Ÿ’ป Code Esimerkkejรค: Opetusalukset toimivat tรคysin C++ ja Python toteutukset, jotka laskevat optimaalisen kiertokulun neljรคn kaupungin vierekkรคisyysmatriisille.
  • ๐ŸŒ Sovellukset: TSP-varianttien sรคhkรถnjakelureittien optimointi, piirilevyjen poraus, DNA-sekvensointi, teleskooppien aikataulutus ja varaston kerรคilyreittien suunnittelu.
  • ๐Ÿค– Tekoรคlyn kulma: Moderni vahvistusoppiminen, graafihermoverkot ja heuristiikat, kuten Lin-Kernighan ja Concorde, ratkaisevat logistiikassa kรคytettyjรค laaja-alaisia โ€‹โ€‹TSP-instansseja.

Matkustavan myyjรคn ongelma

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รค.

Esimerkki TSP:stรค

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

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.
  • V on joukko kรคrkipisteitรค.
  • E on 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รครคrittele cost(i, S, 1) = โˆž varten i โ‰  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) ] varten i โˆˆ S ja i โ‰  j.

Yllรค olevassa kaaviossa vierekkรคisyysmatriisi on seuraava:

Algoritmi matkustavan myyjรคn ongelmalle

dist(i, j)1234
10101520
21003525
31535030
42025300

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.

Algoritmi matkustavan myyjรคn ongelmalle

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^N aliongelmia. Jokaisen aliongelman yhdistรคminen vie lineaarisen ajan. Jos lรคhtรถsolmua ei ole mรครคritelty, tarvitaan ulompi silmukka N solmun yli. Kokonaisaikakompleksisuus on O(Nยฒ ร— 2^N).
  • Avaruuden monimutkaisuus: DP-pรถytรค tallentaa C(S, i) jokaiselle solmujoukon osajoukolle S. On olemassa 2N osajoukkoja solmua kohden, joten avaruuskompleksisuus on O(N ร— 2^N), joka usein kirjoitetaan muodossa O(2^N) kun N:รครค kรคsitellรครคn kiinteรคnรค.

Seuraavaksi tutustu Eratosthenes-algoritmin seula.

UKK

Kauppamatkustajan ongelmassa kysytรครคn lyhintรค kiertomatkaa, joka alkaa valitusta kaupungista, kรคy jokaisessa muussa kaupungissa tรคsmรคlleen kerran ja palaa lรคhtรถpisteeseen. Se on tietojenkรคsittelytieteen benchmark-tyyppinen NP-vaikea optimointiongelma.

TSP on NP-vaikea, koska ei tunneta polynomiaikaista algoritmia, joka ratkaisee jokaisen instanssin tรคsmรคllisesti. Raaka voima -hyรถkkรคys suoritetaan O(n!) ajassa, ja paras tarkka dynaaminen ohjelmointimenetelmรค tarvitsee silti O(Nยฒ ยท 2^N) aikaa, joka kasvaa eksponentiaalisesti.

Dynaaminen ohjelmointi tallentaa vรคlimuistiin lyhimmรคt reitit jokaisen kaupunkien osajoukon lรคpi. Held-Karpin toistumiskustannus(i, S, j) kรคyttรครค uudelleen pienempiรค osaongelmia optimaalisen kierroksen rakentamiseksi, mikรค leikkaa raa'an voiman kustannukset arvosta O(n!) arvoon O(Nยฒ ยท 2^N).

TSP-variantit mahdollistavat viimeisen mailin toimitusreitityksen, varastojen kerรคilyreitit, piirilevyjen porauksen, DNA-sekvensoinnin, teleskooppien aikataulutuksen ja kuorma-autojen lastaussuunnittelun. Kaikki tehtรคvรคt, jotka kรคyvรคt tietyssรค pysรคhdyspaikassa ja palaavat tukikohtaan, ovat TSP-ehdokkaita.

Raaka voima testaa jokaisen kaupunkien permutaation ja palauttaa aina tarkan optimin O(n!) kustannuksella. Lรคhin naapuri hyppรครค ahneesti lรคhimpรครคn vierailemattomaan kaupunkiin O(nยฒ) ajassa, mikรค antaa nopean mutta optimaalista heikomman kierroksen, tyypillisesti 25 % optimaalista nopeamman.

Lin-Kernighan, LKH, Christofides, simuloitu hehkutus, muurahaisyhdyskuntien optimointi ja geneettiset algoritmit tuottavat lรคhes optimaalisia kierroksia suurille TSP-instansseille. Concorde ratkaisee tarkan TSP:n vertailuarvoille kymmenillรค tuhansilla kaupungeilla.

Graafineuraaliverkot ja vahvistusoppimiseen perustuvat agentit, kuten osoitinverkot, oppivat heuristiikkoja, jotka tuottavat kilpailukykyisiรค TSP-matkoja. Ne ovat erinomaisia โ€‹โ€‹strukturoiduissa reittisuunnittelutehtรคvissรค, kuten toimituksissa ja logistiikassa.

Kyllรค. GitHub Copilot ja vastaavat tekoรคlyavustajat tukevat TSP-ratkaisuja C++, Pythontai Java, ehdottaa Held-Karp-muistinmuodostusta ja luo heuristiikkoja, kuten lรคhimmรคn naapurin tai kahden vaihtoehdon vertailuanalyysiรค varten.

Tiivistรค tรคmรค viesti seuraavasti: