Worked examples — A - algorithm — heuristic, admissibility, consistency — important for GNC
Before anything: recall the three quantities from the parent — = cost paid to reach , = guess of cost still owed to the goal, and = guess of the whole trip. A* always pops the frontier node with the smallest . Every example below is just those three letters in a new outfit.
The scenario matrix
Read this table as a checklist of every distinct behaviour A* can exhibit; the "Example" column is the promise that we demonstrate each one, not just assert it. Column meaning: Case class = the condition on the heuristic or graph; What makes it special = the single behaviour you must be able to predict; Example = where it is worked in full.
| # | Case class | Behaviour you must predict | Example |
|---|---|---|---|
| C1 | Admissible + consistent heuristic | optimal path, no re-expansion | Ex 1 |
| C2 | Tie in (goalward vs sideways) | tie-break rule fires; speedup over Dijkstra | Ex 2 |
| C3 | (degenerate) | A* collapses to Dijkstra's Algorithm | Ex 3 |
| C4 | Inadmissible (overestimating) | optimality breaks | Ex 4 |
| C5 | Admissible but NOT consistent | a closed node is re-expanded | Ex 5 |
| C6 | Greedy trap ( only) | small lures into a costly detour | Ex 6 |
| C7a | Dead end (no successors, ) | node examined once, harmlessly abandoned | Ex 7a |
| C7b | Negative edge present | A* / Dijkstra can return a wrong cost | Ex 7b |
| C8 | Real GNC drone, Euclidean | continuous space, consistent, focused cone | Ex 8 |
| C9 | Weighted A* () | bounded suboptimality | Ex 9 |
Example 1 — Grid, Manhattan heuristic (Cell C1)
Forecast: Guess the optimal cost and whether A* ever expands the cell (behind the start).

Step 1. Compute at the start: . So . Why this step? at the start is our first, purely-heuristic estimate of the whole trip. In the figure, inspect the yellow number under — that is this .
Step 2. Expand . Neighbours and their :
- : , , .
- : , , .
- : , , . Why this step? A* keeps the smallest . In the figure, note the two blue cells (goalward, ) versus the pink cell labelled — pink is never touched.
Step 3. Continue popping nodes toward . The path has cost (the yellow arrows in the figure), and along it stays the whole way (consistency keeps flat here). Why this step? Manhattan is consistent on a unit grid: between neighbours the edge cost and , so never dips → no re-expansion.
Verify: True optimum = moves. A* returned . ✔ Backward cell , never expanded. ✔
Example 2 — The tie, and why it means speed (Cell C2)
Forecast: How many cells does plain Dijkstra expand before reaching vs A*?
Step 1. Under Dijkstra (), the frontier grows as a diamond of radius . To reach a node at distance , Dijkstra expands all cells with : that's cells (the diamond ).
Why this step? Dijkstra is blind — it treats every direction equally, so it fills a full diamond. In figure s01, imagine that whole diamond filled; A* instead touches only the handful of cells drawn.
Step 2. Under A*, every backward cell has because moving away raises by as much as rises. The cells that keep are exactly the nodes inside the axis-aligned rectangle spanned by and : that is cells (grid points), namely all with . Why this step? Be careful: we are counting nodes with , not the number of distinct shortest paths. The number of monotone shortest paths from to is the smaller number (choose which of the 3 steps goes upward). A* may touch all 6 rectangle nodes but there are only 3 optimal routes through them.
Step 3. Speedup ratio in nodes expanded . Why this step? This ratio is the payoff of the heuristic — the tie-at- cells are exactly the useful ones. When two of them tie (e.g. vs both at ), our global tie-break rule (larger first, then insertion order) decides the pop order deterministically; either way the answer cost is unchanged.
Verify: Diamond count . Rectangle nodes . Monotone paths . Ratio . ✔
Example 3 — Degenerate : A* becomes Dijkstra (Cell C3)
Forecast: Which node does A* expand second — or ? And is the answer optimal?
Step 1. With , . Expand : put () and () on the frontier. Why this step? is trivially admissible () and consistent, so optimality still holds — we're just unguided.
Step 2. Pop smallest : that's (). Relax : , . Why this step? This is precisely Dijkstra's "pop the cheapest-so-far" rule. contributes nothing.
Step 3. Frontier now . Pop (). Relax : , update to . Why this step? We found a cheaper route to through ; A* (=Dijkstra here) keeps the better .
Step 4. Pop at . Done.
Verify: Path costs: , . Optimum . A* returned . ✔ And it ran exactly Dijkstra — not broken, just blind.
Example 4 — Inadmissible breaks optimality (Cell C4)
Forecast: Will A* find cost (true optimum) or the worse ?
Step 1. Expand . Successors: with ; and directly with . Why this step? The inflated makes the good route look like a 6-cost trip — a lie the search believes.
Step 2. Pop smallest : the direct at beats 's . Since is a goal, A* halts and returns . Why this step? A* trusts . Because overestimated (), it discarded the truly cheaper path.
Step 3. Note the violated condition: admissibility needs , but . Why this step? This is the exact line crossed. The parent's Derivation 1 needed ; break it and the optimality proof collapses.
Verify: True optimum . A* returned — optimality lost, as predicted. ✔
Example 5 — Admissible but NOT consistent → re-expansion (Cell C5)
Forecast: Does A* close once at , then have to re-open it at a cheaper ? What's the final cost?
Step 1. Compute the true remaining costs (the perfect distances to ): (edge ), , . Why this step? We need to test admissibility () — you cannot judge a guess without the truth it estimates.
Step 2. Check admissibility node-by-node: ✔, ✔, ✔, ✔. So is admissible. Why this step? One node over would sink admissibility; all four clear it, so optimality is still guaranteed.
Step 3. Check consistency on edge (cost ): the rule demands . But — violated. So is admissible yet inconsistent. Why this step? Consistency is the stronger triangle-inequality condition; failing it on even one edge means A* may pop a node before its cheapest is settled.
Step 4. Run A*. Expand (): successors with ; and with . This is an tie; by our global tie-break rule (larger first) we pop () before (). We close with and relax : . Why this step? is now closed believing its cheapest cost is — but we have not yet explored the route through . (The tie-break rule choosing first is exactly what sets up the re-expansion; had we popped first, would never have closed prematurely — but a real solver cannot know that in advance.)
Step 5. Pop (). Relax : new , which is cheaper than the closed value . This forces the closed node to re-open, and we re-relax : . Why this step? This is the re-expansion the parent warned about — inconsistency let close too early, so a later cheaper path drags it back onto the frontier.
Step 6. Pop at . Done.
Verify: Optimal path . A* (after re-opening ) returned — optimality preserved (admissible), but it cost one re-expansion (inconsistent). ✔
Example 6 — Greedy best-first trap (Cell C6)
Forecast: Greedy loves the small . Does that path turn out cheap or a trap?
Step 1. Greedy uses only. From : has , has . Greedy pops , then races to : total path cost . Why this step? Greedy ignores the road already travelled (), so it's seduced by the low- node without noticing the giant edge behind it.
Step 2. A* uses . From : has , has . Pop ; relax : . Frontier: . Pop (); relax : , update. Pop at . Why this step? The term makes A* notice the expensive edge — loses to the route.
Verify: Greedy cost . A* / true optimum . A* returned ; greedy returned . ✔ Greedy trap confirmed.
Example 7a — Dead end / blocked frontier (Cell C7a)
Forecast: If looks promising, will A* get stuck?
Step 1. Pin down . From the dead end there is no path to the goal at all, so by our convention . Why this step? Admissibility is . Since , any finite is admissible — even an over-eager that makes look close. There is no finite truth for it to overshoot.
Step 2. Take (deliberately tempting), and . Expand : gets ; gets . Two nodes tie at ; our global tie-break rule breaks by larger (equal here, both ) then insertion order — say entered first, so is popped first. Why this step? We deliberately let the tie hand to the solver first, to prove even the worst-case order is harmless.
Step 3. Pop . It has zero out-edges → it generates no frontier nodes. is simply closed and abandoned. Why this step? A dead end can be examined but never extended; the search naturally moves on to the next-cheapest frontier node.
Step 4. Pop (). Relax : . Pop . Done, cost . Why this step? The dead end cost us one wasted pop but not the answer — A* is complete as long as the goal is reachable and edge costs are nonnegative.
Verify: Only reachable goal path . A* returned . ✔ Dead end contributed nothing but one pop, and was admissible because . ✔
Example 7b — A negative edge breaks A* (Cell C7b)
Forecast: The route through the edge is genuinely cheapest. Will A* find it, or lock in a worse cost?
Step 1. List the true path costs. . direct . . True optimum . Why this step? We compute the ground truth first, so we can catch A* red-handed if it disagrees.
Step 2. Run A* with (Dijkstra). Expand : frontier . Pop (), close it. Relax: ; . Why this step? Dijkstra/A* closes believing is final. With nonnegative edges that belief is safe — here it is about to bite us.
Step 3. Frontier . Pop (), relax : . Update . Pop at . Why this step? In this tiny graph the negative edge happens to still surface, giving . But the mechanism is fragile: had the negative edge dangled off a node that was closed before the cheaper route reached it, A* would never revisit it and would return the too-high .
Step 4. State the failure mode cleanly. A*/Dijkstra's correctness rests on the non-decreasing property (parent's Derivation 2, Step B), which itself needs . A negative edge can lower of an already-closed node, and the closed set will refuse to reopen it → wrong answer in general. Why this step? The point of C7b is the limiting/degenerate case the assumption forbids: with even one negative edge you must switch to Bellman–Ford, which relaxes every edge times and does tolerate negatives (no closed set).
Verify: True optimum . The safe algorithm for negatives is Bellman–Ford, not A*. ✔ (We report here but flag that A* gives no guarantee once .)
Example 8 — Real-world GNC drone, Euclidean heuristic (Cell C8)
Forecast: Is the answer (all straight) or (all diagonal)? And is Euclidean safe on diagonal moves?

Step 1. The cheapest route from to is diagonal steps: cost . In figure s02, this is the blue arrowed diagonal; compare it against the pink L-shaped path (all straight, cost ).
Why this step? Each diagonal step advances both and by for cost , cheaper per unit progress than two straight steps ().
Step 2. Compute at start: — drawn as the dashed straight line in s02.
Why this step? The Euclidean straight line is the shortest possible distance in the plane, so it can never exceed the true grid path cost — hence : admissible.
Step 3. Now verify consistency on the two move types, since an 8-connected grid has both.
- Straight move, e.g. , cost . Euclidean obeys the Triangle Inequality: , and . So . ✔
- Diagonal move, , cost . Again by the triangle inequality with . So . ✔ Why this step? The key insight: consistency needs , and Euclidean distance changes by at most the Euclidean step length, which we deliberately set equal to the edge cost ( for straight, for diagonal). Matching the metric to the cost is what makes it consistent — no re-expansion.
Step 4. How A* explores: because here equals exactly, every off-diagonal cell has strictly larger , so A* expands an extremely narrow cone hugging the blue diagonal — essentially just the true path plus its immediate neighbours. Why GNC cares: a tight admissible+consistent makes A* laser-focused, so an on-board planner with limited compute still returns the genuinely shortest flyable route in real time.
Verify: Optimum . optimum (equal here) ✔. All-straight alternative ✔. Consistency holds on both straight () and diagonal () moves ✔.
Example 9 — Exam twist: Weighted A* (Cell C9)
Forecast: Does inflating by still find the optimum , or trade it for speed?
Step 1. Inflate the heuristic in the priority key: , and . Why this step? Multiplying by makes the search more greedy — it trusts the goal-guess twice as much, so it dives toward low- nodes sooner. The part is untouched.
Step 2. Pop the smaller key first: at beats at . Expand , relax : , key . Why this step? Only now, after actually walking the edge, does the giant cost enter through — the inflated could not warn us because was tiny.
Step 3. Frontier . Pop (), relax : , update 's key to . Why this step? 's inflated key still beat the discovered at , so A* re-examines and finds the genuinely cheaper route. Here the weighting did not cost us the optimum.
Step 4. Pop at key . Weighted A* returns cost . Why this step? We got the optimal answer even at ; weighting only risks suboptimality, it does not force it.
Step 5. State the guarantee. Weighted A* returns a path of cost , where is the true optimum. Here so the bound is . Why this step? This is bounded suboptimality: you may lose optimality, but never by more than the factor . Our sits well inside .
Verify: True optimum . Weighted-A* result . Bound ✔.
Recall Scenario matrix — self-test
Which cell forces a re-expansion? ::: C5 — admissible but not consistent. Which cell makes A* identical to Dijkstra? ::: C3 — . Which cell breaks optimality outright? ::: C4 — inadmissible (overestimating) . Which cell needs Bellman–Ford instead of A*? ::: C7b — a negative edge is present. What is for a dead-end node with no path to the goal? ::: , so any finite there is admissible. In Weighted A* with , the returned cost is bounded by? ::: (bounded suboptimality). What is our global tie-break rule when is equal? ::: pop the larger- (smaller-) node first, then by insertion order.