Floyd–Warshall: kaikkien solmuparien lyhimmät polut
Täyttäkää kaikkien solmuparien etäisyysmatriisi kolmen sisäkkäisen silmukan Floyd–Warshall-algoritmilla ja käyttäkää sitä kaikkien solmuparien pienimmän hyppymäärän etsimiseen.
Floyd–Warshall: kaikkien solmuparien lyhimmät polut on ilmainen DSA Interview Prep-oppitunti CoddyKitissä. Tämä on oppitunti 3/4. Voit lukea tästä oppimispolusta kokonaan mitkä tahansa 3 oppituntia ilmaiseksi — sen jälkeen CoddyKit PRO avaa kaikki oppitunnit sekä käytännön harjoittelun sisäänrakennetulla koodieditorilla ja ympäri vuorokauden toimivalla tekoälytuutorilla. Oppitunti kuuluu DSA Interview Prep-oppimispolkuun, ja edistymisesi synkronoituu verkon ja CoddyKit-sovelluksen välillä. DSA Interview Prep-kurssilla on yhteensä 4 oppituntia.
Kaikkien solmuparien lyhimmät polut
Floyd-Warshall laskee lyhimmät polut jokaisen solmuparin välillä painotetussa graafissa — myös graafeissa, joissa on negatiivisia kaaripainoja, mutta ei negatiivisia syklejä. Dijkstran suorittaminen jokaisesta lähteestä maksaa O(V × (V+E) log V), kun taas Floyd-Warshallin aikavaativuus on O(V³) kaaritiheydestä riippumatta. Tiheissä graafeissa, joissa V ≤ 500, Floyd-Warshall on usein yksinkertaisempi ja suunnilleen yhtä nopea.
Ydinajatus: välisolmut
Floyd-Warshallin keskeinen havainto on seuraava: dp[i][j][k] = lyhin polku solmusta i solmuun j, kun välisolmuina saa käyttää vain solmuja {0, 1, ..., k}. Lyhin polku joko käyttää solmua k välisolmuna tai ei käytä sitä. Jos käyttää: dp[i][j][k] = dp[i][k][k-1] + dp[k][j][k-1]. Jos ei käytä: dp[i][j][k] = dp[i][j][k-1]. Koska kolmas ulottuvuus etenee vain eteenpäin, se voidaan poistaa — päivitykset tehdään paikallaan.
Etäisyysmatriisin alustus
Aloittakaa V×V-matriisilla: dist[i][i] = 0 (etäisyys solmusta itseensä on nolla), dist[i][j] = weight suorille kaarille ja dist[i][j] = inf kaarittomille solmuparien yhteyksille. Käykää sitten läpi kaikki välisolmut k ja päivittäkää solmuparit (i, j). Silmukan k ympärillä on oltava ulommaisena, jotta polut muodostuvat oikein kasvavan sallitun välisolmujoukon kautta.
def floyd_warshall(V, edges):
INF = float('inf')
dist = [[INF]*V for _ in range(V)]
for i in range(V):
dist[i][i] = 0
for u, v, w in edges:
dist[u][v] = w # directed graph
for k in range(V): # intermediate node
for i in range(V):
for j in range(V):
if dist[i][k] + dist[k][j] < dist[i][j]:
dist[i][j] = dist[i][k] + dist[k][j]
return distTäydellinen toteutus esimerkkeineen
Tarkastellaan Floyd-Warshallia neljän solmun graafissa. Kun jokainen välisolmu k on käsitelty, matriisiin muodostuu lyhyempiä polkuja, jotka kulkevat solmun k kautta. Algoritmi käsittelee luonnostaan usean siirtymän polut rakentamalla lyhyimmät polut vaiheittain.
def floyd_warshall(V, edges):
INF = float('inf')
dist = [[INF]*V for _ in range(V)]
for i in range(V):
dist[i][i] = 0
for u, v, w in edges:
dist[u][v] = w
for k in range(V):
for i in range(V):
for j in range(V):
if dist[i][k] != INF and dist[k][j] != INF:
dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j])
return dist
V = 4
edges = [(0,1,3),(0,2,7),(1,2,1),(1,3,5),(2,3,2)]
dist = floyd_warshall(V, edges)
for row in dist:
print([x if x != float('inf') else 'INF' for x in row])Negatiivisten syklien tunnistaminen
Floyd-Warshallin suorittamisen jälkeen tarkistakaa päädiagonaali: jos jokin dist[i][i] < 0, solmun i kautta kulkee negatiivinen sykli. Tämä johtuu siitä, että negatiivinen sykli mahdollistaa paluun solmuun i solmusta i negatiivisella kustannuksella. Jos negatiivisia syklejä ei ole, kaikki diagonaalin arvot pysyvät nollina.
def has_negative_cycle_fw(V, edges):
dist = floyd_warshall(V, edges)
for i in range(V):
if dist[i][i] < 0:
return True # negative cycle through node i
return False
# Negative cycle: 0->1->2->0 with weights 1,-3,1 (sum=-1)
edges_neg = [(0,1,1),(1,2,-3),(2,0,1)]
print(has_negative_cycle_fw(3, edges_neg)) # TruePolun rekonstruointi
Voitte rekonstruoida varsinaisen polun solmusta i solmuun j ylläpitämällä next[i][j]-matriisia: alustakaa suorille kaarille next[i][j] = j. Kun päivitys tehdään välisolmun k kautta, asettakaa next[i][j] = next[i][k]. Polun palauttamiseksi aloittakaa solmusta i ja seuratkaa next-osoittimia, kunnes saavutatte solmun j. Tämä lisää tilavaativuuteen O(V²) ja tekee kunkin polun rekonstruoinnista O(V):n.
def fw_with_path(V, edges):
INF = float('inf')
dist = [[INF]*V for _ in range(V)]
nxt = [[None]*V for _ in range(V)]
for i in range(V): dist[i][i] = 0
for u, v, w in edges:
dist[u][v] = w; nxt[u][v] = v
for k in range(V):
for i in range(V):
for j in range(V):
if dist[i][k] + dist[k][j] < dist[i][j]:
dist[i][j] = dist[i][k] + dist[k][j]
nxt[i][j] = nxt[i][k]
return dist, nxt
def get_path(nxt, i, j):
if nxt[i][j] is None: return []
path = [i]
while i != j:
i = nxt[i][j]; path.append(i)
return pathTransitiivinen sulkeuma
Yksinkertaisempi muunnelma, transitiivinen sulkeuma, vastaa kaikkien solmuparien osalta kysymykseen ”onko solmu j saavutettavissa solmusta i?”. Etäisyydet korvataan totuusarvoilla: reach[i][j] = reach[i][j] or (reach[i][k] and reach[k][j]). Tämä on Floyd-Warshall, jossa yhteenlaskun ja minimioperaation sijaan käytetään totuusarvojen OR-operaatiota. Alustakaa reach[i][i] = True ja asettakaa reach[i][j] = True suorille kaarille.
def transitive_closure(V, edges):
reach = [[False]*V for _ in range(V)]
for i in range(V):
reach[i][i] = True
for u, v, _ in edges:
reach[u][v] = True
for k in range(V):
for i in range(V):
for j in range(V):
reach[i][j] = reach[i][j] or (reach[i][k] and reach[k][j])
return reach
edges = [(0,1,1),(1,2,1)]
R = transitive_closure(3, edges)
print(R[0][2]) # True (0 can reach 2 via 0->1->2)Aikavaativuus ja käyttötilanteet
Floyd-Warshall: O(V³) aikavaativuus, O(V²) tilavaativuus. Tiheissä graafeissa (E ≈ V²), joissa V ≤ 300, tämä on nopeampi kuin Dijkstran suorittaminen V kertaa (myös O(V³) tässä tapauksessa). Harvoissa graafeissa, joissa V = 1000 ja E = 3000, Dijkstran suorittaminen V kertaa maksaa O(V×E×log V) ≈ 33M, kun taas Floyd-Warshall maksaa O(V³) = 10⁹ — Dijkstra on parempi. Tietäkää, milloin kumpaakin algoritmia kannattaa käyttää.
Pienin hyppyjen määrä kaikkien solmuparien välillä
Asettakaa kaikkien kaarten painoksi 1 (tai käyttäkää totuusarvoista vierekkäisyysmatriisia Floyd-Warshallilla ja käyttäkää min-operaation sijaan yhteenlaskua): dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j]). Tämä laskee pienimmän hyppyjen määrän kaikkien solmuparien välillä — tulos vastaa kaikkien parien BFS:ää, mutta se lasketaan yhdellä O(V³)-aikaisella Floyd-Warshall-läpikäynnillä.
def min_hops_all_pairs(V, adj_list):
INF = float('inf')
dist = [[INF]*V for _ in range(V)]
for i in range(V):
dist[i][i] = 0
for j in adj_list[i]:
dist[i][j] = 1
for k in range(V):
for i in range(V):
for j in range(V):
dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j])
return dist
adj = [[1,2],[2],[3],[],[]]
print(min_hops_all_pairs(5, adj)[0]) # [0, 1, 1, 2, INF]Haastattelukonteksti: milloin haastattelijat kysyvät Floyd-Warshallista
Floyd-Warshall tulee haastatteluissa vastaan tehtävissä, joissa: (1) etsitään kaikkien solmuparien etäisyyksiä pienestä graafista, (2) selvitetään, onko graafissa sykliä, jonka kokonaispaino on negatiivinen, (3) lasketaan lyhimpiä polkuja rajoitteiden välitys -ongelmissa tai (4) pyydetään nimenomaisesti O(V³)-aikaista ratkaisua, kun V ≤ 200. Mainitkaa aina kolmen silmukan rakenne sekä se, että oikeellisuus edellyttää negatiivisten syklien puuttumista.
Floyd-Warshall suuntaamattomissa graafeissa
Suuntaamattomissa graafeissa lisätkää jokaisesta kaaresta molemmat suunnat: dist[u][v] = dist[v][u] = weight. Muilta osin algoritmi on sama. Tuloksena oleva matriisi on symmetrinen: dist[i][j] == dist[j][i] kaikille solmuparille. Olkaa alustuksessa tarkkana, ettette vahingossa lisää suunnattuja kaaria — suuntaamattomat kaaret on lisättävä alkumatriisiin molempiin suuntiin ennen kolmen silmukan suorittamista.
def fw_undirected(V, edges):
INF = float('inf')
dist = [[INF]*V for _ in range(V)]
for i in range(V): dist[i][i] = 0
for u, v, w in edges:
dist[u][v] = w
dist[v][u] = w # both directions for undirected
for k in range(V):
for i in range(V):
for j in range(V):
if dist[i][k] + dist[k][j] < dist[i][j]:
dist[i][j] = dist[i][k] + dist[k][j]
return distPikatarkistus
Testatkaa tämän oppitunnin Data Structures & Algorithms — Coding Interview Prep -käsitteiden ymmärtämistä.
Oppitunnin yhteenveto
Tässä oppitunnissa opitte, että Floyd-Warshall laskee kaikkien solmuparien lyhimmät polut kolmella sisäkkäisellä silmukalla ja rekurrenssilla dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j]), negatiiviset syklit voidaan havaita tarkistamalla, onko jokin dist[i][i] < 0 suorituksen jälkeen ja algoritmin aikavaativuus on O(V³) ja tilavaativuus O(V²). Seuraavaksi palaamme lyhimmän polun sovelluksiin Network Delay Timen ja polun rekonstruointitekniikoiden avulla.
Opi Python tekoälytuutorin avulla — ilmaiseksi
Kirjoita ja suorita oikeaa koodia selaimessa, saa välitöntä apua tekoälytuutorilta ympäri vuorokauden ja jatka siitä, mihin jäit, verkossa tai sovelluksessa.
- Kurssit
- 30
- Oppitunnit
- 120
Usein kysytyt kysymykset
Onko oppitunti ”Floyd–Warshall: kaikkien solmuparien lyhimmät polut” ilmainen?
Kyllä — voit lukea täällä verkossa kokonaan ilmaiseksi mitkä tahansa DSA Interview Prep-oppimispolun 3 oppituntia, myös oppitunnin “Floyd–Warshall: kaikkien solmuparien lyhimmät polut”. Sen jälkeen CoddyKit PRO avaa kaikki oppitunnit sekä interaktiiviset harjoitukset sisäänrakennetulla koodieditorilla ja ympäri vuorokauden toimivalla tekoälytuutorilla. DSA Interview Prep-kurssilla on yhteensä 4 oppituntia.
Mitä opin oppitunnilla ”Floyd–Warshall: kaikkien solmuparien lyhimmät polut”?
Täyttäkää kaikkien solmuparien etäisyysmatriisi kolmen sisäkkäisen silmukan Floyd–Warshall-algoritmilla ja käyttäkää sitä kaikkien solmuparien pienimmän hyppymäärän etsimiseen. Harjoittelet DSA Interview Prep-aihetta koodilla, jonka suoritat suoraan selaimessa. Ympäri vuorokauden käytettävissä oleva tekoälytuutori vastaa kysymyksiisi oppitunnin aikana.
Tarvitsenko kokemusta aloittaakseni DSA Interview Prep-opiskelun?
Aiempi kokemus ei ole tarpeen. CoddyKitin DSA Interview Prep-oppimispolku sopii vasta-alkajista edistyneisiin, joten voit aloittaa tästä tai alusta ja edetä omaan tahtiisi. Tämä on oppitunti 3/4.
Kuinka kauan ”Floyd–Warshall: kaikkien solmuparien lyhimmät polut”-oppitunnin suorittaminen kestää?
Useimmat CoddyKitin oppitunnit kestävät noin 5–10 minuuttia. Jokainen oppitunti on lyhyt ja interaktiivinen, joten edistyt tasaisesti ja voit jatkaa siitä, mihin jäit – sekä verkossa että sovelluksessa.
Voinko kirjoittaa ja suorittaa koodia tällä DSA Interview Prep-oppitunnilla?
Kyllä. Jokainen DSA Interview Prep-oppitunti sisältää sisäänrakennetun koodieditorin, joten voit kirjoittaa ja suorittaa oikeaa koodia suoraan selaimessa ja saada välitöntä palautetta tekoälyltä – paikallista asennusta ei tarvita.
Kaikki tämän kurssin oppitunnit
- Dijkstran algoritmi prioriteettijonolla
- Bellman–Ford ja negatiiviset syklit
- Floyd–Warshall: kaikkien solmuparien lyhimmät polut
- Network Delay Time ja polun rekonstruointi