Week 11 · Lecture 14

Shortest paths

Relax weighted edges and understand the condition behind Dijkstra’s algorithm. Contrast single-source and all-pairs questions.

Read alongside the document

Use the lecture headings below in the English–Turkish notes. Document lecture numbers and course week numbers are different.

  • Lecture 14: Shortest Paths
    Warm-up: updating an MST after adding one edge; Why shortest paths matter; Unweighted, weighted, and negative; Dijkstra’s algorithm; Warm-up 2: adding a constant to every edge; All-pairs shortest paths and Floyd’s algorithm.

Download the bilingual notes

When is a tentative shortest distance safe to finalise?

Directed edges A→B=2, A→C=5, B→C=1. Find distances from A.

2 →1 →5 →ABC
The route through B improves the tentative distance to C from 5 to 3.
Step 1

Initial distances: A=0, B=∞, C=∞.

Step 2

Settle A and relax outgoing edges: B=2, C=5.

Step 3

Settle B next; the route A→B→C improves C to 2+1=3.

Step 4

Settle C. Final distances are 0,2,3; predecessor links reconstruct the paths.

Change the case. Dijkstra’s standard settled-once method requires nonnegative weights. With A→B=2, A→C=5, C→B=−4 it can finalise B too early, missing distance 1.

Explain before coding

State the input and required output. Trace a small example. Explain why each step is valid, count the work under a stated model, and test an edge case.

Python support for this week

Use a distance table and predecessor table. A priority queue chooses the smallest tentative distance.

# One relaxation step from the worked example.
d = {"A":0, "B":2, "C":5}
u, v, weight = "B", "C", 1
d[v] = min(d[v], d[u] + weight)
print(d["C"])  # 3

Run this small demonstration after predicting its result. It illustrates the selected example; its input assumptions are part of the example.

Open the optional Python support library. Programming fluency is not required to complete the paper trace.

Read the related bilingual explanations here

Sections from the supplied lecture notes. Turkish paragraphs appear in red. Use this as a reference after the worked example.

Lecture 14 · Warm-up: updating an MST after adding one edge

Hazırlık: Bir kenar ekledikten sonra MST’yi güncelleme

You hold the MST T of a graph G, and a new edge e = (u, v) of weight w is added. Find the MST of G + e in O(n). Adding e to T closes exactly one cycle: the tree path from u to v plus e. The new MST is T + e minus the heaviest edge on that cycle (which might be e itself, in which case nothing changes). Finding the tree path is a DFS on T, which has only n − 1 edges: O(n).

G çizgesinin MST’si T elinizde ve ağırlığı w olan yeni bir e = (u, v) kenarı ekleniyor. G + e’nin MST’sini O(n) sürede bulun. T’ye e’yi eklemek tam bir döngü kapatır: u’dan v’ye ağaç yolu ile e. Yeni MST, T + e’den bu döngüdeki en ağır kenarın çıkarılmasıyla elde edilir (en ağır kenar e’nin kendisi olabilir; bu durumda hiçbir şey değişmez). Ağaç yolunu bulmak, yalnızca n − 1 kenarı olan T üzerinde DFS yapmaktır: O(n).

Lecture 14 · Why shortest paths matter

En kısa yollar neden önemlidir?

Transportation: the cheapest way to travel between two places.

Ulaşım: İki yer arasında seyahat etmenin en ucuz yolu.

Motion planning: the most natural route for a game character through its environment.

Hareket planlama: Bir oyun karakterinin çevresinde izleyeceği en doğal rota.

Communications: how long a message takes between two sites; which two sites are furthest apart (the network’s diameter).

İletişim: Bir iletinin iki nokta arasında ne kadar sürede ulaştığı; hangi iki noktanın birbirinden en uzak olduğu (ağın çapı).

Sentence disambiguation: Skiena’s group reconstructed text typed on a phone keypad where each key stands for several letters. Vertices were candidate words at each position, edges joined possible neighbouring words, and edge weights reflected how likely two words are to be adjacent (“give me” is cheaper than “hive me”). The most probable sentence is the shortest path through this DAG, found by the Viterbi algorithm, which is dynamic programming. The system got over 99% of characters right.

Cümle belirsizliğini giderme: Skiena’nın grubu, her tuşun birkaç harfi temsil ettiği telefon tuş takımında yazılmış metni yeniden oluşturdu. Tepeler her konumdaki aday sözcükler, kenarlar olası komşu sözcüklerin bağlantılarıydı; kenar ağırlıkları iki sözcüğün yan yana gelme olasılığını yansıtıyordu (“give me”, “hive me”den daha ucuzdur). En olası cümle, bu DAG üzerindeki en kısa yoldur ve bir dinamik programlama yöntemi olan Viterbi algoritmasıyla bulunur. Sistem, karakterlerin %99’undan fazlasını doğru belirledi.

Lecture 14 · Unweighted, weighted, and negative

Ağırlıksız, ağırlıklı ve negatif

In an unweighted graph the shortest path uses the fewest edges, and BFS finds it in O(n + m) (Lecture 11). In a weighted graph the length of a path is the sum of its edge weights, and BFS is useless: a path with more edges can be shorter (1 + 1 + 1 + 1 + 1 + 1 + 1 < 10). There can be exponentially many shortest paths between two vertices, so we ask for one, not all.

Ağırlıksız çizgede en kısa yol en az sayıda kenarı kullanır ve BFS bunu O(n + m) sürede bulur (Ders 11). Ağırlıklı çizgede yolun uzunluğu, kenar ağırlıklarının toplamıdır; BFS işe yaramaz: daha fazla kenarlı bir yol daha kısa olabilir (1 + 1 + 1 + 1 + 1 + 1 + 1 < 10). İki tepe arasında üstel sayıda en kısa yol bulunabilir; bu nedenle hepsini değil, birini isteriz.

Negative weights cause trouble. A cycle whose total weight is negative makes “shortest” meaningless, since going round the cycle again always makes the path shorter. This lecture assumes all weights are positive; other algorithms (such as Bellman-Ford) cope with negative edges as long as there are no negative cycles. Minimum spanning trees, by contrast, are unaffected by negative weights.

Negatif ağırlıklar sorun yaratır. Toplam ağırlığı negatif olan bir döngü, “en kısa” kavramını anlamsızlaştırır; çünkü döngüyü bir kez daha dolaşmak yolu her zaman kısaltır. Bu derste bütün ağırlıkların pozitif olduğu varsayılır. Başka algoritmalar (Bellman–Ford gibi), negatif döngü bulunmadığı sürece negatif kenarlarla başa çıkar. Buna karşılık minimum kapsayan ağaçlar negatif ağırlıklardan etkilenmez.

Lecture 14 · Dijkstra’s algorithm

Dijkstra algoritması

The principle: if s → … → x → … → t is a shortest path from s to t, then the part s → … → x must be a shortest path from s to x. (If there were a shorter way to x, splicing it in would shorten the whole path.) So shortest paths are built out of shortest paths to nearer vertices, a dynamic-programming flavour of reasoning.

İlke şudur: s → … → x → … → t, s’ten t’ye en kısa yolsa s → … → x kısmı da s’ten x’e en kısa yol olmalıdır. (x’e daha kısa bir yol olsaydı onu araya koymak bütün yolu kısaltırdı.) Dolayısıyla en kısa yollar, daha yakın tepelere giden en kısa yollardan oluşur; bu, dinamik programlama türünde bir akıl yürütmedir.

Start with d(s, s) = 0. With positive weights, the cheapest edge out of s, say (s, x), gives d(s, x) exactly. Whenever the shortest distance to a new vertex x becomes known, look along each edge (x, y) to see whether going through x offers a shorter way to y.

d(s, s) = 0 ile başlayın. Pozitif ağırlıklarda s’ten çıkan en ucuz kenar, örneğin (s, x), d(s, x)’i tam olarak verir. Yeni bir x tepesine en kısa uzaklık bilinir hâle geldiğinde, x üzerinden gitmenin y’ye daha kısa bir yol sağlayıp sağlamadığını görmek için her (x, y) kenarına bakın.

Dijkstra(G, s, t):
    known = {s}; dist[i] = ∞ for all i; dist[s] = 0
    for each edge (s, v): dist[v] = w(s, v)
    last = s
    while last != t:
        v = the unknown vertex with the smallest dist[]
        for each edge (v, x): dist[x] = min(dist[x], dist[v] + w(v, x))
        last = v; known = known ∪ {v}
Dijkstra(G, s, t):
    known = {s}; her i için dist[i] = ∞; dist[s] = 0
    for her (s, v) kenarı: dist[v] = w(s, v)
    last = s
    while last != t:
        v = dist[] değeri en küçük olan bilinmeyen tepe
        for her (v, x) kenarı:
            dist[x] = min(dist[x], dist[v] + w(v, x))
        last = v; known = known ∪ {v}

This is essentially Prim’s algorithm. In the code, only three lines differ: Prim updates distance[w] with the weight of the single edge (v, w); Dijkstra updates it with distance[v] + weight(v, w), the length of the whole path through v. Run on the slides’ 7-vertex example from vertex A, it produces a shortest-path tree in which the tree path from A to each vertex is a shortest path.

Bu, özünde Prim algoritmasıdır. Kodda yalnızca üç satır farklıdır: Prim, distance[w] değerini tek (v, w) kenarının ağırlığıyla günceller; Dijkstra ise v’den geçen bütün yolun uzunluğu olan distance[v] + weight(v, w) ile günceller. Slaytlardaki 7 tepeli örnekte A’dan başlatıldığında, A’dan her tepeye giden ağaç yolunun en kısa yol olduğu bir en kısa yol ağacı üretir.

Cost. Exactly as for Prim: n rounds, each with an O(n) scan for the minimum and O(n) worth of updates, so O(n²). That is optimal for dense graphs.

Maliyet. Prim’dekiyle aynıdır: her birinde minimum için O(n) tarama ve O(n) güncelleme bulunan n tur, yani O(n²). Bu, yoğun çizgeler için optimaldir.

Faster with better data structures. Keep the fringe vertices in a heap ordered by distance; each of the m edge relaxations may lower a key, costing O(log n), and each of the n extractions costs O(log n): O(m log n), better on sparse graphs. Fibonacci heaps, which lower a key in O(1) amortised time, give O(n log n + m), the best known bound.

Daha iyi veri yapılarıyla daha hızlı. Sınırdaki tepeleri uzaklığa göre sıralanmış bir öbekte tutun. m kenar gevşetmesinin her biri bir anahtarı azaltabilir; bunun maliyeti O(log n)’dir. n çıkarma işleminin her biri de O(log n) sürer: O(m log n), seyrek çizgelerde daha iyidir. Bir anahtarı amortize O(1) sürede azaltan Fibonacci öbekleri, bilinen en iyi sınır olan O(n log n + m)’yi verir.

Lecture 14 · Warm-up 2: adding a constant to every edge

Hazırlık 2: Her kenara bir sabit ekleme

If every edge weight in G goes up by the same constant k, is the shortest-path tree from v still a shortest-path tree? No. A path with more edges pays k more times. A 3-edge path of length 3 beats a 1-edge path of length 4, but after adding k = 10 to every edge the 3-edge path costs 33 and the 1-edge path 14.

G’deki her kenarın ağırlığı aynı k sabiti kadar artarsa, v’den başlayan en kısa yol ağacı hâlâ bir en kısa yol ağacı mıdır? Hayır. Daha fazla kenarlı bir yol, k maliyetini daha çok kez öder. Uzunluğu 3 olan 3 kenarlı yol, uzunluğu 4 olan 1 kenarlı yoldan iyidir; fakat her kenara k = 10 eklenince 3 kenarlı yol 33, 1 kenarlı yol 14 maliyetli olur.

Lecture 14 · All-pairs shortest paths and Floyd’s algorithm

Bütün çiftler arasında en kısa yollar ve Floyd algoritması

Finding the shortest path between one pair (s, t) already requires, in the worst case, finding shortest paths from s to everything. Many applications, such as the centre or diameter of a network, need the distance between every pair. Running Dijkstra from each of the n vertices costs n × O(n²) = O(n³). Can we do better? Not asymptotically, but Floyd’s algorithm is simpler and faster in practice.

Tek bir (s, t) çifti arasındaki en kısa yolu bulmak bile, en kötü durumda s’ten bütün tepelere en kısa yolları bulmayı gerektirir. Ağın merkezi veya çapı gibi birçok uygulama, her çift arasındaki uzaklığa ihtiyaç duyar. Dijkstra’yı n tepenin her birinden çalıştırmak n × O(n²) = O(n³) sürer. Daha iyisini yapabilir miyiz? Asimptotik olarak hayır; ancak Floyd algoritması daha basittir ve uygulamada daha hızlıdır.

It is an instance of the four-step dynamic programming recipe that Lecture 16 develops in full:

Bu, Ders 16’da ayrıntılı olarak geliştirilen dört adımlı dinamik programlama tarifinin bir örneğidir:

Characterise the structure of an optimal solution.

Optimal çözümün yapısını karakterize edin.

Define the value of an optimal solution recursively.

Optimal çözümün değerini özyinelemeli olarak tanımlayın.

Compute the recurrence bottom-up.

Yineleme bağıntısını aşağıdan yukarıya hesaplayın.

Extract the solution from the computed table.

Çözümü hesaplanan tablodan çıkarın.

The set-up. Start from a distance matrix D with D[i, j] = w(i, j) if (i, j) is an edge, 0 if i = j, and ∞ otherwise. This gives shortest paths that use no intermediate vertices.

Kurulum. (i, j) bir kenarsa D[i, j] = w(i, j), i = j ise 0, diğer durumlarda ∞ olan bir D uzaklık matrisiyle başlayın. Bu, hiçbir ara tepe kullanmayan en kısa yolları verir.

The recurrence. Number the vertices 1 to n. Let d[i, j]ᵏ be the length of the shortest path from i to j whose intermediate vertices all come from {1, 2, …, k}. Such a path either avoids vertex k, in which case it was already the best using {1, …, k − 1}, or it goes through k exactly once, in which case it is a best path from i to k followed by a best path from k to j, both using only {1, …, k − 1}:

Yineleme bağıntısı. Tepeleri 1’den n’ye numaralandırın. d[i, j]ᵏ, bütün ara tepeleri {1, 2, …, k} kümesinden seçilen, i’den j’ye en kısa yolun uzunluğu olsun. Böyle bir yol ya k tepesini kullanmaz; bu durumda {1, …, k − 1} ile zaten en iyi olan yoldur. Ya da k’den tam bir kez geçer; bu durumda yalnızca {1, …, k − 1} kullanan en iyi i–k yoluyla en iyi k–j yolunun birleşimidir:

The algorithm is just this recurrence computed for k = 1, 2, …, n, updating the matrix in place:

Algoritma, matrisi yerinde güncelleyerek bu bağıntıyı k = 1, 2, …, n için hesaplamaktan ibarettir:

floyd(D):
    for k from 1 to n:
        for i from 1 to n:
            for j from 1 to n:
                D[i, j] = min(D[i, j], D[i, k] + D[k, j])
floyd(D):
    for k from 1 to n:
        for i from 1 to n:
            for j from 1 to n:
                D[i, j] = min(D[i, j], D[i, k] + D[k, j])

Three nested loops of n: Θ(n³), the same as n runs of Dijkstra, but the loop body is one addition and one comparison, so it wins by a constant factor. Note that k, the “allowed intermediate vertex”, must be the outer loop.

n uzunluklu üç iç içe döngü: Θ(n³), yani Dijkstra’nın n kez çalıştırılmasıyla aynı. Ancak döngü gövdesi bir toplama ve bir karşılaştırmadan oluştuğundan sabit çarpan avantajı sağlar. “İzin verilen ara tepe” olan k’nin en dış döngü olması gerektiğine dikkat edin.

Transitive closure. Replace “min and plus” with “or and and”, and the same algorithm computes which pairs (i, j) are joined by some path: the transitive closure of the graph. This is how a database propagates consequences of facts, as in “is x related to y?”.

Geçişli kapanış. “Minimum ve toplama” yerine “veya ve ve” işlemlerini koyarsanız aynı algoritma, hangi (i, j) çiftlerinin bir yolla bağlı olduğunu, yani çizgenin geçişli kapanışını hesaplar. Bir veri tabanı, “x, y ile ilişkili mi?” örneğinde olduğu gibi olgulardan doğan sonuçları bu şekilde yayar.

Begin with the easy tests and the worked example. Remaining questions provide repeated teaching practice; hard questions are optional depth. Some tests revisit earlier prerequisites. Answers stay visible.

Graph W is undirected: A–B (4), A–C (1), B–C (2), B–D (5), C–D (8), D–E (3), C–E (10). Parenthesised numbers are edge weights.

Practice with answers

10 test questions · 8 written questions · 18 total

Each question is followed by its answer and explanation. Hard questions also include a starting hint and smaller reasoning steps.

Test questions

Choose one option. Cost questions state their model and whether the bound is tight, expected or worst-case. Here lg means log₂, and heap positions start at 1.

Question 1 · easy

For an n-vertex graph, what is the tightest listed worst-case space bound for a full adjacency matrix?

  1. O(n + m)
  2. O(n²)
  3. O(m)
  4. O(n log n)

Answer: option B. One entry per pair of vertices, edge or not.

Question 2 · easy

Shortest paths in an unweighted graph are found by:

  1. BFS
  2. DFS
  3. Prim’s algorithm
  4. Kruskal’s algorithm

Answer: option A. The BFS tree path to each vertex uses the fewest possible edges.

Question 3 · easy

What edge-weight condition ensures the standard settled-once Dijkstra algorithm is correct for every input satisfying it?

  1. all weights equal
  2. no negative weights
  3. a DAG
  4. a tree

Answer: option B. Negative edges break the “nearest unknown vertex is settled” step.

Question 4 · easy

Floyd’s all-pairs algorithm runs in:

  1. Θ(n²)
  2. Θ(n³)
  3. Θ(n log n)
  4. Θ(m)

Answer: option B. Three nested loops over the vertices.

Question 5 · easy · course question

Relaxing edge u→v with weight w means:

  1. Always increase d(v).
  2. Replace d(v) by min(d(v),d(u)+w).
  3. Mark v permanently before comparison.
  4. Delete u.

Answer: option B. The edge offers a candidate route through u; retain it only if it improves the current distance.

Question 6 · easy · course question

A predecessor table in shortest-path search is used to:

  1. Reconstruct a path.
  2. Make negative weights safe for Dijkstra.
  3. Sort the graph.
  4. Count all spanning trees.

Answer: option A. Distances give costs; predecessors record which earlier vertex supplied a chosen route.

Question 7 · easy · course question

An unreachable vertex keeps which shortest-path distance?

  1. 0.
  2. 1.
  3. Infinity.
  4. The number of vertices.

Answer: option C. Infinity denotes that no source-to-vertex route has been found; in the completed search the vertex is unreachable.

Question 8 · medium

Running Dijkstra’s algorithm on graph W from A, the distance to D is:

Graph W is undirected: A–B (4), A–C (1), B–C (2), B–D (5), C–D (8), D–E (3), C–E (10). Parenthesised numbers are edge weights.

  1. 5
  2. 8
  3. 9
  4. 11

Answer: option B. A–C–B–D costs 1 + 2 + 5, cheaper than A–C–D at 9.

Question 9 · hard · optional challenge

Use settled-once Dijkstra, which never changes a settled distance, on A→B (2), A→C (5), C→B (−4). It reports distance to B as ___, but the true shortest distance is ___.

  1. 2 and 1
  2. 1 and 1
  3. 2 and 2
  4. 5 and 1

In simpler words: Trace the vertex that is settled too early.

Starting hint: Compare direct A→B with the later route through C.

Answer: option A. B is settled at 2 as the nearest vertex and never revisited, but A→C→B costs 1.

Step by step
  1. After A, tentative distances are B=2 and C=5. Settled-once Dijkstra freezes B at 2.
  2. The route A→C→B costs 5−4=1. A later negative edge improved a supposedly final distance.

Question 10 · hard · optional challenge

Which statement is FALSE?

  1. a connected undirected graph with distinct edge weights has a unique minimum spanning tree
  2. every minimum spanning tree contains a shortest path between every pair of vertices
  3. BFS tree paths from their root are shortest paths in an unweighted graph
  4. a simple undirected graph is bipartite exactly when it has no odd cycle

In simpler words: Compare the cheapest whole network with the cheapest single journey.

Starting hint: Use a triangle with weights 2,2,3.

Answer: option B. Triangle A–B (2), B–C (2), A–C (3): the MST path from A to C costs 4 while the direct edge costs 3.

Step by step
  1. The MST selects the two weight-2 edges, total 4.
  2. Between the end vertices, the direct weight-3 edge is a shorter path. Minimising total network weight does not preserve every shortest journey.

Written questions

Read each question together with its explanation, trace or proof. Numbering continues from the test questions.

Question 11 · easy

What condition on edge weights does Dijkstra’s algorithm require?

Answer & reasoning

no negative weights. The course assumes all weights are positive.

Question 12 · easy

Match each algorithm with its running time from the notes: Prim (simple implementation), Kruskal with union-find, Dijkstra with a heap, Floyd.

Answer & reasoning

Simple array-based Prim: O(n²). Kruskal: O(m log m) for sorting the edges, with near-linear union-find work. Dijkstra with adjacency lists and a binary heap: O((n + m) log n), often written O(m log n) when all n vertices are reachable and m ≥ n−1. Floyd–Warshall: Θ(n³).

Question 13 · medium

Run Dijkstra’s algorithm on graph W from A. Give the final distance to every vertex and the shortest-path tree.

Answer & reasoning

Distances from A are A = 0, C = 1, B = 3, D = 8, E = 11. A–C–B costs 3, improving the direct edge of weight 4. A–C–B–D costs 8. E has two equally short routes: A–C–E and A–C–B–D–E, both 11. One shortest-path tree uses A–C, C–B, B–D, C–E; choosing D–E instead is also valid. Parent choices depend on the tie rule; strict-improvement-only updates keep C as E’s parent.

Question 14 · medium

Give a small directed graph with one negative edge on which Dijkstra’s algorithm returns a wrong distance, and explain what goes wrong.

Answer & reasoning

A→B (2), A→C (5), C→B (−4). Dijkstra settles B at distance 2 as the nearest unknown vertex and never revisits it, but A→C→B costs 5 − 4 = 1. The greedy step assumes that adding edges can never make a path shorter, which negative weights violate.

Question 15 · medium

Count the number of distinct paths from s to t in a DAG in O(n + m).

Answer & reasoning

Initialise paths[s] = 1 and the other counts to zero. Process a topological ordering; for each edge v→w, add paths[v] to paths[w]. Dependencies are complete when a vertex is processed. This uses O(n + m) arithmetic operations. Path counts can be exponentially large, so arbitrary-precision bit costs are not necessarily constant per addition.

Question 16 · medium

The diameter of a graph is the largest shortest-path distance between any two vertices. How would you compute it for an unweighted graph, and at what cost?

Answer & reasoning

For a connected unweighted graph, run BFS from every vertex and take the largest distance: O(n(n + m)). For a disconnected graph, state a convention: the diameter over all vertex pairs is infinite if unreachable pairs have infinite distance, or report separate component diameters.

Question 17 · medium

Run Floyd’s algorithm on the directed graph with w(1, 2) = 4, w(1, 3) = 11, w(2, 3) = 2. Show what changes at each k.

Answer & reasoning

start with D[1,2] = 4, D[1,3] = 11, D[2,3] = 2, zeros on the diagonal, ∞ elsewhere. k = 1: no entry improves (nothing leads into 1). k = 2: D[1,3] = min(11, D[1,2] + D[2,3]) = min(11, 6) = 6. k = 3: no change (nothing leaves 3). Final shortest distance from 1 to 3 is 6.

Question 18 · hard · optional challenge

Give an O(n + m) algorithm for single-source shortest paths on a DAG, even when some edge weights are negative.

In simpler words: Find shortest paths by processing a DAG in dependency order.

Starting hint: A topological order puts every edge’s start before its end.

Answer & reasoning
Step by step
  1. Set the source distance to 0 and the others to infinity.
  2. At each reachable vertex u, try dist[u]+w(u,v) for every outgoing edge and keep improvements.
  3. All possible predecessors are already processed, so a negative edge causes no late return. Visit each vertex and edge once: O(n+m) word operations.

compute a topological order (O(n + m)). Set dist[s] = 0 and all others to ∞. Process vertices in topological order, and for each edge v→w set dist[w] = min(dist[w], dist[v] + w(v, w)). Every path to w passes through vertices earlier in the order, so dist[v] is final before it is used. Negative weights are harmless because a DAG has no cycles to loop around.