Skip to main content
Artificial Computational Intelligence

Integer Multiplication, Graph Basics, and Dijkstra's Algorithm

Published: 2026-08-09
Level: postgraduate
Audience: Postgraduate students of Artificial Computational Intelligence

Prerequisite Knowledge

This lecture builds on the following concepts from earlier lectures. If any feel unfamiliar, review the linked notes before proceeding.

Previously Covered in This Subject

  • Integer multiplication by divide and conquer — covered in Lecture 9 (Divide and Conquer)
  • Graph search on small graphs (heuristic search worked examples) — covered in Lectures 3 and 4 (Search Algorithms; Heuristic Evaluation and Design)

Integer Multiplication, Graph Basics, and Dijkstra's Algorithm

10.1 Integer Multiplication

10.1.1 Motivation: Why Learn Integer Multiplication?

Under the divide-and-conquer design strategy we have so far covered merge sort and quick sort. Merge sort splits an array in half, sorts each half, and merges the sorted halves. Quick sort splits by a pivot, sorts the two sides, and joins them. Both follow the same pattern: divide the problem, solve the smaller pieces, combine. The third algorithm in this family is integer multiplication, and the natural first reaction is: we all already know how to multiply two integers, so what is the big deal? Why does multiplication deserve its own divide-and-conquer treatment?

Hook. You have multiplied numbers since primary school, and a computer can multiply, too. So why is multiplication the next algorithm in a divide-and-conquer unit, sitting right after merge sort and quick sort? What could a topic this basic possibly gain from being chopped in half over and over?

The answer has two layers. The first layer: a computer must perform multiplication, so the operation itself matters. Every processor carries out millions of multiplications per second, and the way it does so determines how fast programs run. The second and sharper layer: when we talk about integer multiplication here, we mean multiplication of very large integers — numbers so big they cannot be processed in one go in the ALU (arithmetic-logic unit) of a computer. The ALU is the part of the processor that performs arithmetic on machine words, and a single machine word holds a fixed number of bits — typically 32 or 64. A number with hundreds or thousands of bits does not fit into a single machine register, so the elementary-school algorithm we all know — multiply digit by digit and add up the partial products — takes time quadratic in the number of bits: time for two -bit integers. The whole reason for studying multiplication under divide and conquer is to do better than that quadratic wall for such large operands.

Q: We already know how to multiply two integers. Why do we have to learn integer multiplication in a divide-and-conquer unit?

A: Because the computer must perform it — and more importantly, because we are talking about large integers that cannot be processed at one go in the arithmetic-logic unit of a computer. For those numbers the ordinary algorithm is too slow, and divide and conquer gives us a way to beat it.

Real-world: large-integer arithmetic is not a classroom toy. RSA and other public-key encryption algorithms live on multiplication of very large numbers — an RSA key is an integer of hundreds or thousands of bits — which is exactly why the efficiency of this operation matters in practice. The method we develop works in binary, where splitting an -bit number into halves is natural and the shift factors become powers of two.

The shift trick that makes the whole scheme cheap. Multiplying a binary number by is nothing but shifting its bits left by positions. A left shift is a single machine operation — constant time on real hardware, and at most even when we count the bits moved. So every "multiply by " that appears below is cheap: it is a shift, not a real multiplication. That asymmetry — a genuine -bit multiplication is expensive, a shift is nearly free — is the angle to study this algorithm from.

The approach is justified by its time complexity, not by novelty. Multiplication can be done in many ways; we pick this one because it carries an explanation that justifies its runtime. Watch for that pattern throughout this section: every rewrite we perform exists so that the final time-complexity argument becomes clean and provable.

10.1.2 The Elementary Split of an n-Bit Integer

We take an -bit integer and divide it into two halves: the high half (the most significant bits) and the low half (the least significant bits). Do the same for a second -bit integer , giving and . The value of each original number is then:

Here are each -bit integers. Read the equation as a place-value statement: places the high half into the top bit positions, and adding fills the bottom positions. In decimal this is exactly how we write a four-digit number like : the high half 19 sits two digits above the low half 80. This is a recursive process: each -bit half is itself split into two -bit halves, and so on, until we reach single-bit (or single-digit) numbers where multiplication is trivial.

Multiplying the two expansions out gives the transformed product. Let us do the algebra line by line instead of jumping to the answer. Substitute both halves:

The final line is the transformed product:

What did this transformation accomplish? We broke the multiplication of two -bit numbers into four multiplications of -bit numbers — , , , — plus three additions. The additions do not worry us: adding two -bit numbers takes at most time, and we are not paying anything extra for them. Multiplication, on the other hand, cannot be done in time — it is what takes in the school method. That asymmetry — cheap additions versus expensive multiplications — is the entire reason this restructuring is worth attempting.

To make the split concrete in binary, take and . In binary these are 4-bit numbers: and , so and . The split gives , , , , and indeed and . The four sub-multiplications are , , , and , and the equation reconstructs . A quick sense-check: . This is the same process the decimal worked example later in this section runs through in detail.

10.1.3 Naive Divide and Conquer: Four Multiplications

The split of the previous section gives the recurrence for the running time of multiplying two -bit numbers, where the basic operation is multiplication (we count multiplications, not additions):

Here is the time for the four multiplications of -bit numbers, and the term is the time taken by all the other processing — in this case the three additions, which cost at most . The lecture states it in one sentence: the problem of multiplying two -bit numbers is divided into multiplication of four -bit numbers plus some extra processing, and the extra processing is some addition which is equal to ; addition can be done at the max at time. A good habit to practice: explain any recurrence you write in plain English, so that writing it down becomes automatic. If you can say "four subproblems of half the size plus linear extra work" in one breath, you can also write without hesitating.

Applying the master theorem: here (four subproblems), (each subproblem is half the size), and . The master theorem compares with the critical function . Since is polynomially smaller than (case 1 of the master theorem: for ), the recurrence is dominated by the recursive part:

That is an anticlimax: the plain schoolbook algorithm was already running in , and after all this dividing and combining we are back at — no advantage in time complexity. The only thing we gained is the ability to break a size- problem into size- problems at all. Not much of an improvement; but notice that we are not going to change the process at all. The last equation stays exactly as it is. We are only going to rewrite that same equation in a different way, and that rewrite alone will buy us the improvement.

Q: We ended up with quadratic time again after all that work. Why did we do all this?

A: The naive four-multiplication split gives no time advantage by itself — the master theorem lands us back at . But the exercise was not wasted: we proved we can decompose a size- problem into size- subproblems, and now we rewrite the same equation in a form that needs only three multiplications instead of four, and that is where the real gain comes from.

The same lesson appears in an unexpected place — building a heap. The time to build a heap is , not . When we first analyzed the process with a casual, trivial analysis we got ; on a careful, structured, professional analysis we realized it was always . The process did not change between the two analyses — our analysis was the problem. Exactly the same thing is about to happen here: no change in the process, only in the way we look at the equation.

Q: What is the time complexity to build a heap? Why is it not ?

A: It is linear time, . The trivial analysis gave , but careful analysis gives — the process was always the one we were explaining; our first analysis was simply not careful enough. The casual view said " heapify calls, each , so "; the careful view notices that most heapify calls work on small subtrees, and summing the real work over all nodes gives .

Assumption & scope of this recurrence. The recurrence counts only multiplications as the basic operation; additions, shifts, and bookkeeping are absorbed into the term. It assumes is a power of two so that halves are exact (pad the numbers with leading zeros otherwise). And it is a statement about the worst case of the naive four-product scheme: it tells us this particular scheme is no faster than the school method, which is exactly the finding we use to justify the rewrite in the next subsection.

10.1.4 Rewriting the Equation: p1, p2, p3

We keep the exact same process and the exact same last equation. We introduce three variables. Define:

Consider in this form itself — the sum of the halves times the sum of the halves. Expanding it, the products , , , and are all covered, which is why was defined that way: one product term contains all four ingredients we need. Now subtract and from :

The two high-by-low cross terms survive and everything else cancels — this is exactly the middle term of the expanded product. So we can write the full product using only :

Check that this matches the original expansion term by term: sits at the position (the high place), sits at the position (the middle), and sits at the position (the low place). Nothing changed mathematically — the product is the same number — but the way we compute it is about to become cheaper.

Now count what each piece costs, and count carefully. is two -bit additions plus one -bit multiplication — consider in its non-expanded form, otherwise you will think there are many multiplications inside it. is one -bit multiplication, and is one -bit multiplication. The whole equation then contains three -bit multiplications, two subtractions, and two additions. The multiplications by and are just left shifts — constant-time operations that account for at most time in total, so we do not even need to count them separately.

Pitfall — counting inside the expanded form of . When you count multiplications, must stay as : two additions plus one multiplication. If you expand it into and then count the multiplications there, you will count four multiplications inside alone, conclude the scheme needs more products than before, and lose the entire point of the rewrite. This exact trap was called out in the session — the non-expanded form is the whole trick.

The improved recurrence is:

with the now covering all the additions and subtractions of the multiplication process. By the master theorem with , , , the critical exponent is :

The lecture states the value as " power log 3 to the base 2", which solves to about or ; precisely, , so the running time is . From down to may look like a modest gain in a trivial analysis, but for integers of very large size it is a solid improvement — although it seems slower initially because of the extra pre-computations (dividing the -bit number into halves, doing the additions and subtractions), for very large integers this multiplication saves a considerable amount of time. For smaller integers the overhead of the splitting, additions, and subtractions can outweigh the benefit, so the normal multiplication algorithm is the right choice there; this divide-and-conquer version is for large integers. The method is known as the Karatsuba algorithm, published by Karatsuba and Ofman in 1962, and it is the standard example of beating a naive method by restructuring the arithmetic rather than the process.

Q: Are the additions and subtractions not also of bits? Should the equation not be ?

A: The term at the end of the equation is the time that accounts for whatever processing happens other than the basic operation, and its maximum time complexity is — it will not exceed . We cannot strictly restrict it to , because there can be other processing time as well: the shifts, the bookkeeping of the recursion, and the additions and subtractions together stay within , and is the honest upper bound.

Comparison: the three multiplication schemes side by side.

Scheme Sub-multiplications Combine work Recurrence Total time
School method single-digit products adding partial products
Naive divide-and-conquer 4 products of bits 3 additions
Rewritten (Karatsuba-style) 3 products of bits 2 subtractions + 2 additions

When to pick which: the school method wins for small integers, where the overhead of splitting and recombining is not worth it; the three-product divide-and-conquer wins for large integers, where the improved exponent pays off. The naive four-product scheme is a stepping stone, not a competitor — its only value is showing that the process itself can be decomposed, which sets up the rewrite.

Visual intuition — why one fewer multiplication changes the exponent. Draw the recursion trees for the two recurrences. For , each node of size spawns 4 children of size , so at depth there are subproblems each of size . The tree has levels; at the bottom there are leaves of size 1 — the quadratic wall. For , each node spawns 3 children instead of 4; the depth is still , but the bottom level has only leaves. Plot the two growth curves and for from 1 to : they look close at small and visibly diverge at large — at , but , about 8000 times smaller. That gap is exactly what the "for very large integers" caveat means.

10.1.5 The Integer Multiplication Algorithm

The algorithm as a procedure. The algorithm mirrors the derivation exactly, so the recurrence is visible in the code itself.

  • Purpose: multiply two large integers and in better than quadratic time by splitting them in half and recombining three products.
  • Inputs: two integers and ; let be the maximum of the size of (in bits) and the size of — the largest number of bits among the two.
  • Output: the product .
  • Steps:
  1. If , return the product as such — a single-bit multiplication is the base case and needs no division.
  2. Otherwise split: is divided into and (two -bit halves), and into and .
  3. Compute the three products: , , .
  4. Combine: return .

There are exactly three multiplications of -bit numbers in the algorithm — one in each of — and the rest is additions and subtractions, which is why the recurrence is and why the recurrence must be clear: three multiplications of -bit numbers, two subtractions, and two additions.

Note that the slide's listing names the products differently from the derivation above: here is the low product and is the high product , while in the derivation was the sum-product and was the low product . Only the names are swapped — the algebra is identical. In the listing's naming, is exactly the cross term, placed at the position between the low product and the high product . Whichever naming you use, the equation is the same product, so pick one naming per solution and stay consistent with it.

Q: What will be the base condition for this recursion?

A: When the number of digits in the multiplication is one — when it is a single-digit multiplication — you do not need any division, so you return the product directly. That is why the recursion stops there. With one digit on each side, the product is a basic fact (like or ), and dividing further would not help.

Q: Does the textbook give the integer multiplication explanation?

A: Yes, it does — but do not make it very complex by going line by line through it. If the concept is clear from this session, then going through the textbook becomes easy. The textbook treatment of big-integer multiplication uses the same split and the same three-product trick; it may write the sum-product with a minus sign (such as ) instead of a plus sign, but that is the same cross term after cancellation.

Decimal works identically to binary, with the base swapped: in the decimal worked example the factor becomes because the base is 10. You should convert the decimal numbers of the example into binary and redo the process — with binary the shifts become powers of two, and the shift-by-two-positions effect becomes literal bit shifting.

Exam note: the recurrence construction — explaining in plain English why it is and then why the rewritten equation gives — and the master-theorem evaluation of both are the exam-worthy core of this topic. Practice writing the recurrence in plain English, and practice the binary version of the worked example; the binary homework was assigned for exactly this reason.

10.1.6 Worked Example: 1980 × 2315 in Decimal

The lecture works only the first iteration or two in class because a full recursion is tedious, and deliberately uses decimal so the writing goes faster — the process is exactly the same as binary, not easier. The multiplication is , both four-digit numbers, so and in base 10. The full walkthrough below follows the derivation's naming: is the sum-product, the high product, the low product.

Step 1 — split into halves. splits into high half and low half . splits into and . Check: , .

Step 2 — compute p1, p2, p3.

Step 3 — recurse on . Split and . Then:

Step 4 — recurse on . Split and . Then:

Now every multiplication left is single-digit, so the recursion is over: is computed directly, no further recursion.

Step 5 — combine one level up (). Using the combine equation with and (two-digit numbers, ):

Substituting: . Check: . This result will be substituted back into the next level up.

Step 6 — combine at the level. The two single-digit products and are already known, and just arrived:

Check: . This is for the top level.

Step 7 — the remaining recursions. The two other sub-multiplications, and , must each go through the recursive steps and come back — the lecture leaves that as the tedious remainder. Working them out with the same method:

: split into and . Then , , , and combining gives . Check: .

: split into and . Then , , , and combining gives . Check: .

Step 8 — the top-level combine. The top-level combine equation, with and for four-digit numbers, is:

Substituting , , :

Sense-check. The answer is the true product , confirming the equation. Quick verification by a different route: . ✓

The lecture stops the in-class walkthrough after the first iterations because the process is long but mechanical; the important part is being clear on the first iteration. Notice how the recursion unwound: we went down to single digits on one branch (), combined it, then used the result inside the next combine — and the same unwind happens independently inside and . If you convert the same numbers to binary and rerun the process, the factors become , and each multiply-by-a-power-of-two becomes a plain shift.

10.1.7 Beyond This Algorithm: FFT-Based Multiplication

For anyone interested, there is an even faster approach: using a more complex divide-and-conquer algorithm called the fast Fourier transform (FFT), two -bit integers and can be multiplied in time. The idea is to treat the bit strings as polynomials, multiply the polynomials with the FFT in time, and read off the integer product from the coefficients — the same divide-and-conquer family, applied to the coefficients instead of the bits. This is only for information and optional reading for those curious — FFT itself is a topic studied in later coursework, but the fact that multiplication can be driven down to shows the same design strategy pushing further. (For exactness: the best-known FFT-family algorithms for integer multiplication run in time; is the clean picture the theory points toward.)

Real-world: FFT-based multiplication is what arbitrary-precision arithmetic libraries actually use for gigantic operands — libraries such as GMP that back big-integer arithmetic in programming languages switch to FFT-based methods once the operands grow past tens of thousands of digits. The same divide-and-conquer idea we built here underlies the big-integer arithmetic inside RSA-style encryption systems, where the operands are the hundreds- or thousands-of-bits integers that cannot be processed at one go in the ALU — the motivation we started with.

Recap and bridge. Integer multiplication showed the divide-and-conquer playbook at full strength: split into halves, count what the naive split costs, then rewrite the same equation to drop the number of subproblems from four to three, and the master theorem rewards you with instead of . The lesson generalizes: when a recurrence looks flat, look for a way to reduce , the number of recursive calls, before touching anything else. Next, we move from numbers to networks — graphs — and from there to the first greedy graph algorithm.

10.2 Graph Basics

10.2.1 What Is a Graph?

Hook. How would you draw a map of the internet, a city's road system, or who-knows-whom in a company? All of these reduce to the same picture: dots and lines between them. That picture, made precise, is a graph — and it is the single most reusable modeling tool in this course.

A graph is an ordered pair , where is a set of nodes called vertices and is a collection of pairs of vertices called edges. The order matters in the pair itself: names the vertex set first and the edge collection second. The word "collection" rather than "set" is deliberate — a collection may hold two identical pairs, which is how we allow parallel edges later. For implementation purposes, vertices and edges are positions and stored elements: a position is an abstract data type (ADT) that can store elements, so when you implement a graph in code, each vertex and each edge can be a position that stores data — a vertex can store its name, a number, or anything else, and an edge can store the weight of that edge.

Q: What are positions?

A: A position is an abstract data type (ADT) that can store elements. When you actually implement a graph in a program, the vertices and edges can be positions — each vertex stores its name or value, and each edge can store its weight. The position ADT is a generic container: it knows it holds an element, and it supports operations to read and replace that element, without caring what the element is.

The running example is an airport network: each vertex represents an airport and stores its three-letter airport code, an edge represents a flight route, and the numbers written on the edges are the mileage of the routes. So a graph has vertices, edges, and edges can carry values or weights.

Real-world: graph modeling appears everywhere — electronic circuits (printed circuit boards), transportation networks (for example the road route between two cities), highway networks, flight networks, computer networks (a LAN is a network; the internet is the biggest example), and databases (an ER diagram: an employee entity type and a department entity type are vertices, and the relationship "employee works for a department" is the edge connecting them). In every case the modeling decision is the same: identify the objects (vertices) and the relationships between objects (edges).

10.2.2 Directed, Undirected, and Mixed Edges

A directed edge is an ordered pair of vertices. The first vertex is the origin and the second vertex is the destination, shown with an arrow from to . Example: a flight operating between two airports only in one direction — say a flight from one city to another that does not come back the other way — is a directed edge; it goes from the origin to the destination only.

An undirected edge is an unordered pair of vertices. Example: a route existing between two airports — the route can be traveled both ways, like a bridge connecting two places, where you can go from place A to place B and back.

A mixed graph has both kinds of edges in one graph. The important skill is deciding, from the nature of the question, whether you are modeling a directed graph or an undirected graph — you must logically visualize the statement. The moment you see the words "flight route", do not conclude "directed" automatically: if only a route exists between the places, you can model it as undirected; it is the actually operating flight that must be a directed edge. In a directed graph all the edges are directed; in an undirected graph all the edges are undirected.

Choosing the edge type: the three options side by side.

Edge type Formal definition How to draw it Example When to pick it
Directed ordered pair arrow from to operating flight, one-way street, inheritance movement or flow in one direction only
Undirected unordered pair plain segment route, bridge, two-way street, collaboration movement or flow in both directions
Mixed both kinds in one graph arrows and segments together city map one-way and two-way streets coexist

When to pick which: read the scenario and ask whether the relationship can be traversed in reverse — one direction means directed, both directions means undirected, and a mixture in one scenario means mixed.

Q: When we see a flight route, should we always model it as a directed graph?

A: No — do not think that a flight route is always directed. If it is only a route existing between the places, you can consider it as undirected; if there is a flight actually operating between the airports in one direction, then you must consider it as a directed edge. The deciding question is whether movement is possible in both directions or only one: a route allows travel both ways, an operating flight with a scheduled direction allows only one way.

The same situational judgment applies to electrical wiring and water pipes: model them as directed or undirected depending on whether the current, or the water, is allowed to flow in both directions or only one direction. For water, in principle it can flow either way through a pipe, so an undirected edge is natural unless the system is built for one-way flow.

Visual intuition. Picture the airport example as a chart: vertices drawn as labeled circles (three-letter codes like SFO, LAX, PVD), edges drawn either as plain line segments (route exists both ways) or as arrows (operating flight from origin to destination). The shape of the drawing does not matter — what matters is which pairs are connected and whether the connections are arrows or plain segments.

10.2.3 Graph Terminology: Endpoints, Incidence, Adjacency, Degree

The terminology builds layer by layer, each term defined from the earlier ones. For an edge with endpoints and : and are the end vertices (or endpoints) of that edge. In the sample graph, and are endpoints of the edge labeled .

Edges incident on a vertex: the edges that touch that vertex. In the sample undirected graph, the edges , , and are incident on vertex . The edges incident on vertex are , , and — the two parallel edges shared with and the self-loop at (both defined below).

Adjacent vertices: two vertices joined by an edge. and are adjacent (edge ); another pair is and (joined by edge ).

Degree of a vertex: the number of edges incident on that vertex. In the sample graph, vertex has degree 5 — the edges are all incident on it. The degree of vertex is left as a quick exercise — count the edges touching : — four edges, so .

Terminology practice on the sample graph. Work each term on the figure before reading the answer.

  • Endpoints: and are the endpoints of edge .
  • Incident edges: edges , , and touch vertex , so they are incident on .
  • Adjacency: (edge ) and (edge ) are adjacent pairs.
  • Degree: vertex is touched by edges — five edges, so .
  • Edges incident on : the parallel edges and (both joining and ) and the self-loop at — three edges, and because the self-loop counts twice, .

Every answer follows from the same figure: count the edges that touch the vertex, and for a self-loop remember both of its endpoints sit on the same vertex.

Reading the sample graph. The sample graph used throughout this section has six vertices and ten edges labeled through : , , , , , , , , (parallel to ), and (a self-loop). Every terminology check below — endpoints, incidence, adjacency, degree, parallel edges, self-loop, paths, cycles — is answered from this one figure, so keep it in view while reading.

Visual intuition. Draw the graph as a loose hexagon: at the top, and below it, and at the bottom, off to the side. Connect to (edge ) and to (edge ); connect to (edge ) and to (edge ); connect to (edge ) and to (edge ); connect to (edge ) and to twice (edges and running side by side); and draw a loop from back to itself (edge ). The two parallel edges and appear as two separate curves between the same two circles; the self-loop appears as a small circle attached to alone.

10.2.4 Parallel Edges and Self-Loops

Parallel edges are edges having the same endpoints — in the sample graph, the edges and are parallel edges, both joining the same two vertices and . Parallel edges appear in real graphs naturally: two flights on the same route at different times of day are parallel edges in the airport graph, one per flight, between the same two airports.

A self-loop is an edge whose endpoints are the same — in the sample graph, the edge is a self-loop; its two endpoints are the same vertex . A self-loop in a city map is a street that curves around and returns to its own starting intersection.

Q: When there is a self-loop, do we count it as 1 degree or 2 degrees?

A: Count it as twice, because in an undirected graph each edge is counted twice — once for each endpoint — and a self-loop has both endpoints on the same vertex. This is exactly why the sum of degrees of all vertices equals : every edge contributes two counts, and a self-loop contributes both of its counts to the same vertex.

A graph with no self-loops and no parallel edges is called a simple graph. Most of the graphs we analyze in this course are simple, but the definitions must handle the exceptions: when a graph is not simple, the degree counting rule still works — the self-loop just lands both of its counts on one vertex.

10.2.5 Paths and Cycles

A path is a sequence of alternating vertices and edges. It begins with a vertex and ends with a vertex, and each edge in the sequence is preceded and followed by its endpoints.

A simple path is a path in which all its vertices and edges are distinct — no vertex and no edge is repeated. Example from the sample graph: the path (following the blue-colored edges) is a simple path. The longer walk is a path but not a simple path, because the vertex is repeated.

A cycle is a circular sequence of alternating vertices and edges — a path that comes back to its starting point. A simple cycle is a cycle in which all vertices and edges are distinct other than the starting vertex; the cycle concept itself accounts for the starting vertex being repeated, since a circular sequence must return to where it began. The blue-colored cycle in the sample graph is a simple cycle; the brown-colored one is not a simple cycle because a vertex is repeated inside it. So the rule of thumb: in a path no vertex can be repeated; in a cycle, only the starting vertex may be repeated.

Terminology at a glance.

Term Definition Sample graph instance
Endpoints (end vertices) the two vertices an edge joins are the endpoints of edge
Incident edge an edge that touches a vertex edges are incident on
Adjacent vertices two vertices joined by an edge ,
Degree number of incident edges ,
Parallel edges edges with the same endpoints and between and
Self-loop edge whose endpoints coincide edge at
Simple path path with all vertices and edges distinct
Simple cycle cycle with all vertices distinct except the start the blue cycle

Visual intuition. Trace the blue path on the sample graph: a pencil that never leaves the circles and never revisits one. Now trace the brown walk : the pencil revisits , so the walk is not simple. For cycles, imagine a circular tour of the graph — it must close on itself, so the starting circle is revisited by definition, and that single repeat is the only one allowed for simplicity.

10.2.6 Modeling Real Scenarios as Graphs

Three worked modeling decisions show how to choose directed, undirected, or mixed:

Co-authorship (undirected). Build a graph whose vertices are researchers of a discipline and whose edges connect pairs of researchers who have co-authored a paper or book. This is undirected because collaboration is a symmetric relation: if author A has co-authored something with B, then B has definitely co-authored that same thing with A. There is no direction to the edge because the relationship cannot hold in one direction only.

Inheritance (directed). In object-oriented programming, the inheritance relation between classes is directed — the edges are directed because inheritance only goes in one direction; it is an asymmetric relation. If class inherits from class , the arrow points from to (or from the parent to the child, depending on convention), but the reverse relationship does not hold: does not inherit from .

City map (mixed). A city map is modeled by a graph whose vertices are intersections and dead ends and whose edges are stretches of streets without intersections. This is a mixed graph: there can be one-way streets, which give directed edges, and streets allowing traffic in both directions, which give undirected edges. A mixed graph is rare, but here the situation demands it — and it is your job, based on the situation, to take that call.

Q: When we see a flight route, should we always model it as a directed graph?

A: No — do not think that a flight route is always directed. If it is only a route existing between the places, you can consider it as undirected; if there is a flight actually operating between the airports in one direction, then you must consider it as a directed edge. The relation's symmetry decides the graph type: symmetric relations (collaboration, a two-way route, a two-way street) model naturally as undirected edges; asymmetric relations (inheritance, a one-way street, a scheduled flight) model naturally as directed edges.

The same situational judgment applies to electrical wiring and water pipes: model them as directed or undirected depending on whether the current, or the water, is allowed to flow in both directions or only one direction. When in doubt, ask "can this relationship be traversed in reverse?" — yes means undirected, no means directed, both in one graph means mixed.

Exam note: expect to be asked which graph type a given scenario needs — the decision rule is symmetry (both directions) versus asymmetry (one direction only). Practice by reading a scenario, naming the vertices and edges, and then arguing the direction choice from the relation itself, exactly as the three examples above do.

10.2.7 Three Key Properties

These properties matter later for algorithm analysis, so they are worth being thorough about.

Property 1 — sum of degrees. For any undirected graph with edges:

The sum of the degrees of all the vertices equals twice the number of edges. Reason: each edge is counted twice — once for each of its endpoints — so the total is , and this holds for every undirected graph.

Sum-of-degrees check. Take the six-edge sample graph . Then . Reading the figure vertex by vertex: (edges ), (edges ), (edges ), (edges ), (edges ), (edges , plus the self-loop counted twice). Sum: . And . ✓ The simpler version worked in the lecture — four vertices each of degree 3 on a graph with edges: — checks the same identity on a smaller figure.

Property 2 — simple graph edge bound. A simple graph is a graph with no self-loops and no multiple edges — between two vertices there cannot be more than one edge. If is a simple graph with vertices and edges:

The number of edges is at most on the order of . Take a simple graph and work it out to confirm the bound: with vertices, the maximum is edges. The exact maximum depends on the edge type: for a simple undirected graph, the tight bound is (each of the ordered vertex pairs collapses to one unordered pair), while is the exact maximum for a simple directed graph, where the ordered pairs and count as two distinct edges. The lecture's statement is the directed bound and, for either type, a valid upper bound of order — which is what the algorithms later in the course actually use.

Property 3 — in-degree and out-degree. For a directed graph with edges, define in-degree of a vertex as the number of edges incoming to it, and out-degree as the number of edges outgoing from it. Then:

For directed graphs we do not talk about "degree" (all incident edges) because incident includes both incoming and outgoing; instead we use in-degree or out-degree, and each of those sums equals the number of edges — not . This makes logical sense without computation: every edge contributes exactly one incoming count at its destination and one outgoing count at its origin. A practice graph was given for homework: compute in-degrees and out-degrees for every vertex and verify both sums — five minutes of practice is enough, and it is assigned, not optional.

Assumptions and pitfalls of the three properties.

  • Self-loops and Property 1: the sum-of-degrees identity holds because a self-loop is counted twice for its single vertex. Counting it once breaks the equation by one.
  • Parallel edges and "simple": parallel edges make a graph non-simple. If the problem statement says "simple graph", parallel edges and self-loops are forbidden by definition — and if it does not, the edge bound does not apply.
  • Directed graphs: never apply Property 1 to a directed graph — a directed edge is not counted twice the same way. Use in-degree and out-degree, each summing to , never to .
  • The bound is about order, not exactness: for algorithm analysis what matters is that ; the half-factor between undirected and directed does not change the asymptotic picture.

Visual intuition. Imagine counting handshakes at a party: every handshake (edge) involves two hands (endpoint counts), so the total number of hands involved is twice the number of handshakes — that is Property 1. For a directed graph, imagine one-way deliveries: each delivery is received once (in-degree count) and sent once (out-degree count), so the total received equals the total sent equals the number of deliveries.

10.2.8 Weighted Graphs and More Applications

A weighted graph is a graph in which each edge has an associated numerical value called the weight of the edge — it can represent distance, cost, and so on. In the airport example, the weight of an edge represents the distance in miles between the endpoint airports. Weighted graphs are the models used when the relationships have a cost or quantity attached: a road graph with travel times, a network graph with cable costs, a flight graph with mileage.

Real-world: weighted-graph modeling shows up in movie preference systems — viewers are one set of vertices and movies are another set of vertices; there is an edge from a user to a movie if the user viewed that movie, and the edges are weighted by the rating the viewer gave. This is a bipartite structure: edges only ever join a viewer vertex to a movie vertex, never two viewers. Nobody restricts you to drawing a graph in a perfect grid — a graph can be drawn any way that is convenient to read, as long as vertices and edges are clear. More examples worth reading through on your own build the intuition for modeling scenarios as graphs.

Recap and bridge. A graph is an ordered pair : vertices with stored data, edges with optional weights, each edge directed or undirected according to the symmetry of the relation it models. Three counting identities — sum of degrees , the edge bound, and the in/out-degree sums — tie vertices and edges together and will be used as tools when we analyze graph algorithms. Next we put graphs to work: the first greedy graph algorithm, Dijkstra's single-source shortest path.

10.3 Dijkstra's Algorithm

10.3.1 The Single-Source Shortest Path Problem

Hook. Suppose you know the road network of a country — every town, every road, every distance in kilometers — and you want to know the cheapest route from your town to every other town at once. You could plan each trip separately, but a single algorithm can answer all of them in one run. That algorithm is Dijkstra's algorithm.

The first algorithm under graphs is the single-source shortest path algorithm — Dijkstra's algorithm. Given a graph and a starting vertex , the algorithm computes the shortest distance from to every other vertex: the output is the shortest distance from to , from to , from to , and so on — the distances of all the vertices from a given start vertex . "Single source" is the key phrase: one start vertex, many destinations. The output is not one path but a complete answer set — the shortest distance to every vertex, plus enough bookkeeping to recover the paths themselves.

Two assumptions are required. The graph must be connected — if the graph were two disconnected pieces, you could not compute a distance from to vertices in the other piece, since no path exists. And the edge weights must be non-negative — the reason for this is examined in detail after the algorithm is understood; other algorithms allow negative weights, but Dijkstra needs non-negative edges.

Assumption & scope. Dijkstra's algorithm applies when (1) the graph is connected, so every vertex is reachable from the source, and (2) every edge weight is non-negative, so adding an edge to a route can never make it cheaper. If either condition fails, the algorithm either cannot run (disconnected graph: the unreachable vertices have no answer) or silently gives wrong answers (negative weights: shown in detail in 10.3.8). A third scope point: the algorithm computes single-source, all-destinations distances — for a single pair it still runs and stops early once the destination is extracted, but the design and the analysis target all destinations.

Real-world: this problem is the mathematical core of GPS navigation. A navigation app is given the road graph with travel-time weights and computes the shortest route from your current position — the single source — to the destinations you care about, using exactly the machinery developed here.

10.3.2 Relaxation of an Edge

The heart of Dijkstra's algorithm is a procedure called relaxation of an edge. We relax an edge with weight . Each vertex carries two pieces of information: , the cost of reaching from the source — the best distance found so far — and , the predecessor of on that best route. (For the moment, take the current cost values as already computed; the procedure that sets them comes next.)

The relaxation check for a directed edge from to is:

In words: if the already-calculated cost of reaching from the source is greater than the cost of reaching through — that is, the cost of reaching plus the weight of the edge — then the route through is cheaper, so update the cost of to and record the predecessor of as . If the check fails, nothing happens: the current route to is already at least as good as the route through , so both and stay unchanged.

Formalizing the three cases. Relaxing edge with weight compares two candidate costs for : the stored value and the through- value .

  • If : the route through wins. Update and set .
  • If : the two routes tie. Either route is shortest, so no update is needed.
  • If : the stored route wins. Leave both and alone.

The comparison uses strict greater-than; ties do not trigger an update, and that is fine because the two routes cost the same.

Worked numbers, first case (update). Suppose the cost of reaching from the source is 8, the cost of reaching from the source is 11, and the edge has weight 2. The check: is ? Yes. So we update , because we found a route to that is cheaper than the previously known one, and we set — the predecessor of is , meaning you should come to through .

Worked numbers, second case (update). The cost of reaching is 5, the edge has weight 2, and the cost of reaching through some other path is 9. Since , the better route exists, so is updated to 7 and the predecessor becomes .

Worked numbers, third case (no update). The cost of reaching is 5 and the edge weight is 2, so the route through costs 7 — but an alternate route reaches at a cost of 6, which is less than 7, so we do nothing: the relaxation step leaves both and unchanged.

Relaxation in one picture. Draw two vertices and , with the current cost written inside each vertex and the edge weight written on the arrow. Before the relaxation on the left: , , . The through- route costs , so after relaxation becomes 10 and becomes . Before the relaxation on the right: , , . The through- route costs , so nothing changes. One sentence to take away: relaxation keeps the best known cost, and it never increases a cost — values only ever stay or drop.

This relaxation step is the most important step of Dijkstra's algorithm — if you do not understand it, you will not understand the algorithm at all. Everything else in the algorithm exists to decide which edges to relax in which order; the relaxation itself is the only place where distances and paths are ever improved.

Why "relaxation"? The intuitive picture: the edge had a very high cost attached; we relax it to have a cheaper cost, which is closer to our goal of shortest paths.

Q: Why is it called a relax process?

A: The exact origin of the name is not something we can be sure about. Conceptually, though, we are relaxing that edge to have a cheaper cost — the cost was very high, and we relax it down to a value closer to our aim, like relaxing ourselves toward reaching the goal. One way to see it: the algorithm maintains the constraint for every edge; when the constraint is already satisfied there is no "tension", the edge is relaxed, and nothing needs to be done — only when the constraint is violated do we tighten the value to restore it.

Real-world: the commute analogy — if you know two places and two routes between them, whichever route is cheaper to reach the place becomes your updated shortest path. That everyday decision is exactly the relaxation step. You hear a new route to a shop costs less than the route you knew; your mental "distance to the shop" drops and the route you remember changes to the new one.

10.3.3 Initialize Single Source

The second building block is the procedure initialize single source. For every vertex in the graph, we start by assuming that no vertex is reachable from the source. Concretely:

  • — the cost of reaching the source from the source itself is zero.
  • For every other vertex , — conceptually none of the vertices are reachable from the source.
  • For every vertex, — if a vertex is not reachable, there is no question of a predecessor.

That is the starting point of the algorithm. The infinity is not a number to be reached — it is a flag meaning "no route known yet". Because every real route has finite cost, the first relaxation that finds any route to will satisfy and install the first real value. This is why the strict-greater-than comparison works with infinity: any finite number beats it.

Q: How do we find , the weight of the edge?

A: The weights of the edges will be given — otherwise we would not be able to run the algorithm. The graph arrives complete with its edge weights (as in the worked example below: every edge carries a stated number of kilometers), so relaxing an edge means looking up its weight, not computing it.

10.3.4 The Algorithm

With relaxation and initialization understood, the algorithm is short:

  1. Initialize single source: set , and for all other vertices.
  2. Let (the visited list) be empty, and put all the vertices of the graph into . is just an array of vertices — no special data structure is needed at this point.
  3. While is not empty:
  • Extract the minimum from : pick the vertex with the smallest current distance . This vertex is now processed — add it to the visited list.
  • For every vertex adjacent to (for every edge connected to ), relax the edge : apply the check of Section 10.3.2, updating and if a cheaper route through exists.

The algorithm as a procedure.

  • Purpose: compute the shortest distance from the source to every other vertex of a connected, non-negatively weighted graph.
  • Inputs: a graph with vertex set , edge set , non-negative weights on every edge, and a source vertex .
  • Outputs: for every vertex , the shortest distance from and the predecessor that encodes the shortest-path tree.
  • Steps: initialize single source; fill with all vertices; repeatedly extract the minimum-distance vertex from , add it to the visited list, and relax every edge out of . Stop when is empty.
  • Cost: the loop body runs times; with an array implementation the total is , with a heap implementation — both analyzed in Sections 10.3.6 and 10.3.7.

That is the whole algorithm — it writes exactly the steps we would perform by hand. The two subtleties to keep hold of: the extracted vertex is the minimum-distance vertex among those still unvisited, and relaxation may change costs and predecessors of other unvisited vertices. Note the second point carefully: extracting a vertex fixes its own distance forever, but it also improves the distances of its neighbors — which is why later extractions can and do find already-improved values.

Visual intuition — the growing cloud. Imagine the visited vertices as a shaded cloud that starts with just and swallows one vertex per iteration, always the unvisited vertex with the smallest current distance. Each new vertex drags its unvisited neighbors closer to the cloud by relaxing its outgoing edges. The algorithm ends when the cloud covers everything. This cloud picture is exactly the one used in Section 10.3.8 to explain why negative weights break the algorithm.

10.3.5 Worked Example on a Five-Vertex Graph

Run Dijkstra's algorithm on the directed graph with vertices and the following directed edges and weights: weight 10, weight 3, weight 4, weight 8, weight 2, weight 9, weight 2, weight 1, weight 7. The source is . Relate the vertices to places you know and the weights to kilometers — that is all the graph is.

Step 0 — initialize. ; ; all predecessors nil.

Step 1 — pick A (min, ). Relax the outgoing edges of . Edge : is ? Yes — so , . Edge : is ? Yes — so , . State: .

Step 2 — pick C (min remaining, ). Relax 's outgoing edges , , . Edge : is ? Yes — so , . Conceptually: reaching by going costs 7, cheaper than the direct at 10. Edge : is ? Yes — so , . Edge : is ? Yes — so , . State: .

Step 3 — pick E (min remaining, ). Relax 's only outgoing edge : is ? No — is reachable more cheaply via . Nothing is updated.

Step 4 — pick B (min remaining, ). Relax 's outgoing edges and (do not forget ). Edge : is ? Yes — so , . Reaching through from is cheaper than reaching through . Edge : is ? No — nothing changes.

Step 5 — pick D (min remaining, ). Relax 's only outgoing edge : is ? No — nothing changes.

Final distances and paths by backtracking predecessors. The shortest paths are recovered by following the last-updated predecessor pointers backward from each destination. : , , so the shortest path is . : , so is just the direct edge. : , , , so is . : , , so is .

Sense-check of every final value. via costs , and the direct edge costs 10 — 7 wins. costs 3, the cheapest possible since it is a direct edge. via then costs , while via directly costs 11 — 9 wins. via costs , while any longer route costs more — 5 wins. The final distances are , , , , . ✓

This backtracking is the aim of the algorithm — nobody will update these after the algorithm ends, so you must explicitly write out or highlight the shortest paths in the diagram. Note the order in which vertices were processed: — always the minimum-distance vertex among those remaining. The minimum was read from the current, up-to-date values: after Step 2 the unvisited candidates were , so came next even though 's value was known earlier.

Q: The first time we did C to B, there were two routes — weight 4 and weight 1. Why did we choose 4?

A: C to B is a directed edge with weight 4; the weight 1 edge is the reverse direction, B to C. There is only one edge from C to B, so only the weight 4 is considered when relaxing C's outgoing edges. The arrow matters: a directed graph stores a one-way edge per direction, and when we relax the outgoing edges of we only look at edges that leave .

Visual intuition. Draw the five vertices at the left, just below it, to the right of , to the right of , and between and . Label every edge with its weight and every arrowhead. After the run, the shortest-path tree (the edges used by the final routes: , , , ) forms a tree rooted at — each vertex except the source has exactly one incoming tree edge, its predecessor. Highlighting these four edges is the "explicitly write out the shortest paths" step.

10.3.6 Time Complexity: Array Implementation

Analyze Dijkstra's algorithm step by step, assuming is implemented as an ordinary array or linked list.

Initialize single source: we must set for every vertex one by one, which forces us to visit all vertices at least once — so this step takes time, where is the number of vertices.

The while loop: it runs until is empty, and holds all vertices, so the loop body executes times.

Find and remove the minimum: finding the minimum element of an array takes time (no sorting needed — just scan). Doing this once per loop iteration gives time for the two statements together.

Relaxation over edges: the for loop relaxes each edge of the graph at most once. How many edges can a vertex be connected to? At most the total number of edges — the degree of a vertex is bounded by the number of edges . Using the earlier property: in a directed graph the sum of in-degrees of all the vertices is , so the total relaxation work is — not , because the already accounts for the sum of in-degrees of all vertices. This is where the degree property pays off.

Total for the array implementation:

Since dominates , the time complexity of Dijkstra's algorithm with an array is .

Instantiate the analysis on the five-vertex worked-example graph: vertices and edges. Initialization costs about 5 steps, the loop runs 5 times, each extract-min scans up to 5 entries ( scan steps total), and the relaxation loop examines each of the 9 edges once. The total is on the order of steps — dominated by the from the scans, exactly as the formula predicts. For a dense graph with near , the term swallows everything.

Q: What is the time taken to find the minimum element from an array?

A: It takes order of n time — you scan the whole array to find the smallest value, and we do not need to sort it first. One pass through the array, keeping a running champion, finds the minimum in exactly comparisons.

Visual intuition. Finding the minimum of an array is like scanning a shelf of price tags for the cheapest item: you look at every tag once and remember the best so far — no rearranging needed. That is steps per scan, and Dijkstra performs such a scan once per extracted vertex.

10.3.7 Time Complexity: Heap Implementation

We know a better data structure for extracting the minimum: the heap, also known as a priority queue. Re-run the analysis with implemented as a heap.

Initialize single source: still — and the build-heap time of is accounted for right here inside initialization; while building the heap we can set all the initial distances at the same time.

The while loop: still iterations.

Find and remove the minimum: extracting the minimum from a heap takes time. That is where the difference appears: instead of per extraction we pay , so the loop plus extraction costs instead of .

Relaxation as decrease-key: each relaxation of an edge is nothing but decreasing the key of a vertex in the heap — during the worked example the costs only went down (10 to 7, infinity to 3), never up. The heap has procedures called increase-key and decrease-key, and changing the value of a node in a heap requires a heapify that takes time. So for each edge the relaxation costs , and over all edges it costs .

Together:

The last step uses the degree property again: in a connected graph the sum of degrees of all vertices is , and in a directed graph the sum of in-degrees (or out-degrees) is , so the total degree is upper-bounded by the number of edges — which is definitely the upper bound — so can be replaced by alone. So the heap-based implementation runs in .

Q: Where are we accounting for the build-heap time?

A: Inside initialize single source. Build heap takes time, and while building the heap itself you can do the initialization — the two happen together. Building the heap and setting every are both linear-time passes over the vertices, so one pass does both jobs.

Comparison: array versus heap implementation.

Component Array / linked list Heap
Initialize single source (includes build-heap)
Extract minimum, per vertex
Extractions over the whole run
Relax each edge (decrease-key) per edge, total per edge, total
Total

When to pick which: for dense graphs, where is close to , the array implementation's is fine and simpler; for sparse graphs, where is close to , the heap implementation's is far faster. The heap wins whenever the graph has few edges per vertex.

10.3.8 Why Edge Weights Must Be Non-Negative

The basic principle on which Dijkstra's algorithm works: if all the weights are non-negative, adding an edge can never make a path shorter. Every time the algorithm finds the node with the lowest cost and relaxes its outgoing edges, it adds the edge weight onto the already-accumulated cost — an addition process. If every added amount is non-negative, the cost of reaching a place can only grow as we go further, so the cost of a place we have already reached will never be reduced later. That guarantee is exactly why picking the shortest candidate at each step always ends up being correct.

What if some weights are negative? Consider the small graph: source , edges weight 4, weight 1, weight 5, and weight . From , . Processing 's incident edges: and . Now the visited vertices form a "cloud" — the shaded area of already-processed vertices, whose outgoing edges have all been relaxed. Next the minimum is at 5, so is processed and its processing is over; only later is reached at 9, and relaxing gives — C's cost drops from 5 to 1 after C has already been finalized. The frozen vertex can no longer be reprocessed, so the algorithm silently keeps the wrong answer. Even one or two negative edges break Dijkstra's algorithm: as per the greedy method, the processing of was done, and we cannot redo it.

The cloud argument, stated sharply. Dijkstra's correctness rests on one claim: when a vertex is extracted, its distance is final. This claim is true exactly when no later relaxation can lower that distance — which holds when every edge weight is non-negative, because every future route to the extracted vertex must pass through edges that only add cost. A negative edge breaks the claim: it can sneak a cheaper route to a vertex that was extracted earlier, like the edge sneaking the route at cost after was already frozen at 5. Reprocessing the vertex would fix it, but the greedy rule forbids revisiting — so the wrong answer stands.

The negative-edge counterexample, step by step. Vertices: (source), , , . Edges: weight 4, weight 1, weight 5, weight .

  • Initialize: , .
  • Extract : relax .
  • Extract (4): relax ; relax .
  • Extract (5): is finalized at 5; it has no outgoing edges to relax.
  • Extract (9): relax — is ? Yes — the correct cost of is 1, but has already been extracted and frozen.

The algorithm reports . The true shortest distance from to is 1, via the negative edge. Wrong answer, no warning. Try solving the same graph once with on the edge and once with , and the difference becomes direct: with , the route costs , never beats the frozen 5, and the algorithm is correct. ✓

Q: What if some weights are negative and some are non-negative?

A: It will not work. We need all the weights to be non-negative for Dijkstra's algorithm to work. There are other algorithms where edge weights can be negative — one such algorithm is Bellman-Ford, covered in the assigned self-study material, which you must go through. Bellman-Ford handles negative weights (as long as no negative cycle is reachable) by relaxing every edge times, which costs — slower than Dijkstra, but not limited to non-negative weights.

Q: When do we freeze a node?

A: We process a node — all its outgoing edges are relaxed — as and when we pick the minimum vertex from the remaining set. In the negative-edge example, C was processed with the value 5, then later reaching F made C's value 1, which would force us to reprocess C — and that is exactly the failure. A node is frozen the moment it is extracted; its value must never need to change again, and that is only guaranteed with non-negative weights.

If all the edge costs are the same, the algorithm still works and remains optimal.

Q: When all the costs are the same, is the result still optimal?

A: Yes — every path costs the same, so any path you take is optimal. If every edge costs , a path with edges costs , and the shortest path is simply the path with the fewest edges — any such path is as good as any other. Dijkstra extracts vertices in order of hop count, exactly like a breadth-first traversal, and the answer is optimal.

10.3.9 Greedy Strategy

Under which design strategy does Dijkstra's algorithm fall? We have studied two design strategies so far — the greedy method and divide and conquer. Dijkstra's algorithm is a greedy method. The reason: our ultimate aim is the shortest path from the source to all other vertices, and we keep picking the minimum — extract-min, the minimum-cost vertex — under the assumption that picking the shortest path or shortest edge will always end up getting the shortest global path. We do not even consider the destination initially; we are only worried about the current vertex's incident edges, and out of those we pick the shortest edge, assuming we will end up with the shortest path for the whole graph. Local optimality is leading to global optimality — that is the defining feature of the greedy method.

Greedy at work in Dijkstra's algorithm. A greedy algorithm builds a solution step by step, committing to the best local choice at every step and never revisiting it. In Dijkstra's algorithm, the local choice is "extract the unvisited vertex with the smallest current distance and freeze it"; the never-revisiting rule is the visited list. The global guarantee — that the frozen distance is final — is exactly what non-negative weights provide, as Section 10.3.8 showed. Contrast with divide and conquer: there, the solution is built by combining solutions of subproblems, not by committing to local choices.

The greediness also explains the failure mode: a greedy algorithm is only as good as its local-choice rule, and when a negative edge makes a frozen vertex's value drop later, the "never revisit" rule becomes a bug rather than a feature. The same greedy pattern returns in the next session with the second greedy graph algorithm — minimum spanning tree — which also commits to cheapest edges, never revisits them, and needs the same careful justification of why the local choice is safe.

10.3.10 Applications of Dijkstra's Algorithm

Real-world: Dijkstra's algorithm is everywhere in practice. OSPF (Open Shortest Path First), the routing protocol used in IP networks, is built on it. GPS and geographical maps use it, and so does the A* algorithm — a well-known path-finding algorithm and an advanced version of Dijkstra itself; Google Maps does not directly use Dijkstra but uses A*, a version of Dijkstra whose basic concepts remain the same. All routing algorithms and all path-finding algorithms for computing the distance between two places can use this approach. There is also an interactive visualization tool worth playing with to see how Dijkstra behaves on a practical example — watch the visited "cloud" grow as the algorithm runs.

Recap and bridge. Dijkstra's algorithm solves the single-source shortest-path problem on connected graphs with non-negative weights by repeatedly extracting the minimum-distance vertex and relaxing its outgoing edges. Its cost is with an array and with a heap; its correctness rests on the non-negative-weight guarantee; and its strategy — commit locally, never revisit — is the greedy method, the same strategy behind the minimum spanning tree algorithms that come next. Before the next session, read the minimum spanning tree material: it is the second greedy graph algorithm, and it will be covered quickly.

Exam Guidance Summary

  • Quiz 2: scheduled for the window from 5th November to 10th November, 30 minutes, 20 questions. It will contain questions from graph topics — so the basics of graphs and Dijkstra's algorithm are directly quiz material.
  • Integer multiplication: the recurrence construction and master-theorem evaluation are exam-worthy; practice writing the recurrence in plain English and practice the binary version of the worked example. The exam-worthy core is the two recurrences — and the improved — and the master-theorem evaluation of each.
  • Graph basics: expect scenario questions that ask you to decide directed vs undirected vs mixed, plus the three properties — sum of degrees equals , the simple-graph edge bound, and in-degree/out-degree sums. The practice graph for in/out degrees was assigned; work it out.
  • Dijkstra's algorithm: expect analysis questions comparing the array implementation with the heap implementation , the relaxation mechanism, and the reason non-negative weights are required. The two greedy graph algorithms — shortest path and minimum spanning tree — are both really important not only from the exam perspective but from an application perspective as well.
  • Minimum spanning tree: read about MST before the next session — it will be covered very quickly, since it is the second greedy graph algorithm.
  • Self-study video material is mandatory: the class runs in flipped mode — sessions cover topics that are not explained in detail in the self-study videos, and questions will come from those self-study topics as well. There is no list of "important" videos; all of them matter equally, like a contact session. Bellman-Ford (negative-weight shortest paths) is one such topic — it appears in the self-study material and must not be ignored.
  • Textbook problems are exam material: exam questions are taken from the textbook without warning — for example, the "criminal robot" style question on the mid-sem exam was a textbook exercise problem. The stock-span problem will be there, and the clue for it was already given in class. Textbook problem solutions are not provided — you have to work them out.
  • Marks distribution: there is no hard percentage rule between pre-mid-sem and post-mid-sem topics, but the intention is to include more from post-mid-sem topics.
  • Comprehensive exam: open book. Feedback about question comprehensibility has been noted and will be addressed in the comprehensive exam.
  • Assignment: submission requires a design document justifying your choices; wherever the assignment says binary tree, you may use a binary search tree instead if it gives better efficiency — justify that selection in the design document. Assignment date extension is not possible.
  • Course reality check: this is a five-credit course with many topics; it will be difficult, especially for those without a computer-science background. The last session is 12th November, possibly with one extra session if needed.

Key Industry Applications

  • Integer multiplication / RSA: the divide-and-conquer multiplication (and its FFT variant) powers the large-integer arithmetic at the heart of RSA encryption algorithms; in binary the split is natural and shifts become powers of two.
  • FFT-based multiplication: fast Fourier transform gives multiplication of two -bit integers — used in arbitrary-precision arithmetic for very large operands.
  • OSPF routing: Open Shortest Path First, a core internet routing protocol, is an application of Dijkstra's algorithm.
  • GPS and map navigation: Dijkstra-style shortest path computation underlies GPS and geographical maps.
  • A* algorithm / Google Maps: A* is an advanced version of Dijkstra; Google Maps uses A*, whose basic concepts remain the same as Dijkstra's.
  • Path-finding in general: all routing algorithms and path-finding algorithms for distance between two places use this approach.
  • Graph modeling: electronic circuits (printed circuit boards), transportation and highway networks, flight networks, computer networks (LAN, the internet), and ER diagrams in databases are all graphs — entities are vertices, relationships are edges.
  • Movie preference systems: viewers and movies as two vertex sets, with rating-weighted edges — a weighted-graph model of recommendations.
  • Research collaboration networks: co-authorship graphs connect researchers who have published together — undirected because collaboration is symmetric.
  • The commute analogy: choosing the cheaper of two known routes to a place is relaxation in everyday life.

DSA Lecture 10 notes · Integer Multiplication, Graph Basics, and Dijkstra's Algorithm

Data Structures and Algorithms· postgraduate· 2026-08-09

Sections Breakdown

110.1 Integer Multiplication

Why large integers need more than the schoolbook algorithm: the split into halves, the naive four-product recurrence, the three-product rewrite (Karatsuba), the full decimal worked example, and FFT-based multiplication.

210.2 Graph Basics

Graphs as ordered pairs of vertices and edges; directed, undirected, and mixed edges; terminology, paths and cycles, modeling scenarios, and the three counting properties.

310.3 Dijkstra's Algorithm

Single-source shortest paths: the problem, relaxation of edges, initialization, the extract-min loop, a full worked example, array and heap implementations, and why non-negative weights are required.

4Exam Guidance Summary

Quiz and examination logistics: what is exam-worthy in each topic, mandatory self-study material, and textbook problems.

5Key Industry Applications

Where the lecture's ideas show up in industry: RSA and big-integer arithmetic, OSPF routing, GPS navigation, A*, and graph modeling.

Postgraduate students of Artificial Computational Intelligence

Exam Revision Notes

Below is the distilled, exam-ready core. Every entry comes from the full explanation above. Use this section for rapid review; return to the main notes when a point needs more context.

Integer Multiplication

Must-know: Rewrite the product equation so that three half-size multiplications replace four: define p1=(ih+il)(jh+jl), p2=ih*jh, p3=il*jl, then i*j = p2*2^n + (p1-p2-p3)*2^(n/2) + p3, giving T(n)=3T(n/2)+Theta(n)=Theta(n^1.585).

⚠️ Top pitfall: Counting multiplications inside the expanded form of p1 = (ih+il)(jh+jl); p1 must be counted as two additions plus one multiplication.

Self-check: Why does the naive four-product split give Theta(n^2) and the rewritten three-product split give Theta(n^1.585)?

Connects to: 10.2, 10.3

Graph Basics

Must-know: Decide graph type by relation symmetry (undirected = both ways, directed = one way), and know the three properties: sum of degrees = 2m, simple-graph bound m <= n(n-1) (directed; n(n-1)/2 undirected), and in/out-degree sums each equal m.

⚠️ Top pitfall: Counting a self-loop as one degree in an undirected graph — it counts twice, once per endpoint; and applying the degree sum 2m to directed graphs, which use in/out-degree sums of m.

Self-check: Why is the co-authorship graph undirected while the inheritance graph is directed?

Connects to: 10.1, 10.3

Dijkstra's Algorithm

Must-know: Dijkstra works by extract-min + relax: the extracted vertex is frozen forever, which is only safe when all edge weights are non-negative; costs are O(|V|^2) with an array and O(|E| log |V|) with a heap, and the strategy is the greedy method.

⚠️ Top pitfall: Relaxing a directed edge in the wrong direction (e.g., using the weight-1 reverse edge B->C when relaxing C's outgoing edges), and forgetting that negative edges break the frozen-cloud guarantee.

Self-check: Why is the heap implementation O(|E| log |V|) rather than O(|V|^2)? What does relaxation do when d[v] <= d[u] + w(u,v)?

Connects to: 10.2, 10.1

Exam Guidance Summary

Must-know: Quiz 2 runs 5th-10th November (30 min, 20 questions) with graph topics; recurrence construction for integer multiplication, scenario questions for graph types, and Dijkstra analysis questions are exam-worthy; MST must be read before the next session.

⚠️ Top pitfall: Treating self-study videos as optional — the flipped-mode class assumes them and exam questions come from them, including Bellman-Ford.

Self-check: When is Quiz 2, and which topics does it cover?

Connects to: 10.1, 10.2, 10.3

Key Industry Applications

Must-know: Integer multiplication with its FFT variant powers RSA large-integer arithmetic; Dijkstra-based shortest paths power OSPF, GPS, and A* (used by Google Maps).

⚠️ Top pitfall: Claiming Google Maps runs plain Dijkstra — it runs A*, whose basic concepts remain the same as Dijkstra's.

Self-check: Which routing protocol is an application of Dijkstra's algorithm?

Connects to: 10.1, 10.3

Was this lecture useful?

Loading comments…
🤖

BitsNotes AI Assistant

Subject Notes Assistant

Configure AI Chat

Choose how to access the chatbot
Have your own API key?

Switch to "Bring Your Own Key" tab above for unlimited access with any OpenAI-compatible provider.

🔑 Enter API key above to fetch live models from provider, or enter model name manually.
OpenAI-Compatible API Support

Choose any provider preset (Gemini, DeepSeek, Kimi, GLM, MiniMax, Qwen, OpenAI, Groq, Ollama, etc.) or enter a custom endpoint URL.

Security & Privacy First

Your API key is sent directly from your browser to your specified provider. BitsNotes servers never store or see your key.