Answers · Making it fast enough
Why doesn't breadth-first search give the cheapest path once the links have different costs?
In shortBreadth-first search counts links rather than costs, so it can return a route with fewer links that is more expensive than a longer route.
Breadth-first search, the ring walk, counts links, not costs, so it can return the one-link route that costs 120 minutes while a two-link route costs 25. It is not broken. It is answering how few links, and once links have different costs that is no longer the same question as how little time or money.
The two questions diverge
Take three towns. The first has a direct road to the third taking 120 minutes. It also has a road to the second taking 10 minutes, and the second has a road to the third taking 15 minutes. The direct route uses one link. The route through the second uses two links and costs minutes. Breadth-first search meets the third town through the direct road at depth one and marks it visited. It therefore never considers the two-link route, even though that route is cheaper by minutes.
| route | links used | total cost in minutes | found by breadth-first search |
|---|---|---|---|
| direct road | 1 | 120 | yes |
| through the second town | 2 | 25 | no |
The natural guess is that fewer hops must mean less cost. That guess is exactly what breadth-first search encodes. Its waiting line is served in arrival order, so the first time it reaches a town it fixes the smallest number of links to that town. A later route with two links and total 25 arrives after the one-link route with total 120, and the visited mark prevents the 25 from replacing the 120. The problem is not that breadth-first search is careless with the costs. It does not look at the costs at all.
Serve the line by cost
The repair is one substitution. Keep a best known cost for every town, zero at the start and infinity elsewhere. Take from the waiting line the town with the smallest best known cost, not the one that joined first. For each neighbour, test whether the cost through the current town is lower than the best known cost, and if it is, record the lower cost and put the neighbour in the line. This is the same walk as before except that the line is ordered by cost rather than by arrival.
| step | step | cheapest in the line | its cost | improvements from it | best known costs | what happened |
|---|---|---|---|---|---|---|
| 1 | 1 | a | 0 | b to 4, c to 1 | b 4, c 1 | Start at a with cost 0. The link to b costs 4 and the link to c costs 1. |
| 2 | 2 | c | 1 | b to 3, d to 7 | b 3, d 7 | c is cheapest in the line at 1. Going c to b costs 2, so b becomes 3. Going c to d costs 6, so d becomes 7. |
| 3 | 3 | b | 3 | d stays 7 | d 7 | b is cheapest at 3. Going b to d costs 4, so the candidate is 3+4=7, which does not improve on 7. |
| 4 | 4 | d | 7 | e to 9 | e 9 | d is cheapest at 7. Going d to e costs 2, so e becomes 7+2=9. |
| 5 | 5 | e | 9 | nothing left | all settled | There are no further improvements. |
At the second step the route to b is already known at 4, from a directly. Going through c costs , so the 4 is replaced by 3. That replacement is the part breadth-first search has no equivalent of. A town can enter the line more than once before it is finally settled, and the stale entry is ignored when it surfaces. At the end the costs are a 0, c 1, b 3, d 7, e 9. The route to d through c costs ; the route to d through b costs , so it does not improve. The route to e through d costs .
Why the cheapest in the line is safe
When a town comes out of the line as the cheapest, at cost , the method declares it settled. Suppose a later route reached more cheaply. That route must leave the settled region through some town still in the line, because is outside the settled region until now. Since was the cheapest in the line, . The rest of the route from to has total link cost , so it costs . If every link cost is nonnegative then , hence . No later route can be cheaper.
The condition is , not that the graph is connected or small. If a link can be negative, the proof fails and the method fails silently. Take a to b cost 1, a to c cost 4, b to c cost 5, and c to b cost . Cheapest first settles b at 1. Later it reaches c at 4, then finds b at , but b has already been settled and is never revised. The output still says b costs 1, though a to c to b costs . Nothing raises an error. Negative costs occur when steps earn money or release a resource. The method for those relaxes links repeatedly and detects a loop that lowers cost forever.
Give every link the same cost and the two methods agree. The cheapest-first walk then settles towns in exactly the order the ring walk visits them, because cost and link count rise together. Breadth-first search is the special case that is cheap to run when all links cost the same, and it is the wrong tool as soon as they do not.
Worth keeping
- Breadth-first search minimises the number of links, not the sum of link costs.
- Serving the waiting line by cheapest known cost repairs this, provided no link has negative cost.
- With a negative link the method can settle a town too early and return a wrong answer without any error.
Where this goes next
This question is one step of Graphs and Finding a Path, a course that works through its subject from the beginning. The page that teaches this part of it is When Some Links Cost More, and it reads the whole way through whether or not you have an account.
What an account changes is the practice: problems standing under every idea, marked with a reason rather than a tick, in a copy of the course that is yours.
Read that pageThe whole courseOther questions people ask about this
- Why does breadth-first search always find the path with the fewest links?Breadth-first search meets points in order of how many links they are from the start, so the first time it reaches a point it has used the fewest possible links.
- How do I know when there is no order that satisfies all the dependencies?If you repeatedly remove anything with nothing still waiting on it and cannot remove everything, the dependencies contain a loop, so no valid order exists.
- How do I find out if a graph is really in two separate pieces?Walk from one point, mark everything you can reach, then start again at any unmarked point; the number of walks is the number of separate pieces.
- Why is it safe to keep taking the cheapest link that doesn't create a loop?Because the cheapest link joining two separate pieces is the cheapest way across a split, and swapping it into any rival solution cannot raise the total cost.
- Why is O(2n) treated the same as O(n)?Because it describes how cost grows rather than exact cost, doubling every cost does not change the growth class.
- How does a hash function turn a word into an array index?A hash function reads the word as bytes, mixes them into one large number, then takes the remainder after dividing by the table size to get an index from zero to size minus one.