Artificial Intelligence · Unit II

Search Techniques in AI

Uniform search, heuristic strategies, local optimisation, constraint satisfaction, and adversarial games — with full traces and worked examples

TextbookRussell & Norvig — Chapters 3, 4, 5, 6
TopicsUniform Search · Heuristic Search · Local Optimisation · CSP · Adversarial Search
Section 01

Uniform (Uninformed) Search Strategies

Imagine you are dropped in an unfamiliar city and asked to reach a hospital. You have no map — just the ability to see the roads directly around you. You could explore every street systematically (BFS), or dive down one road as far as it goes before backtracking (DFS). These two intuitions correspond precisely to the foundational uninformed (or uniform) search strategies — algorithms that explore the state space without any domain-specific hints about which direction is "closer" to the goal.

Before comparing strategies, we establish four universal evaluation criteria. Every search algorithm in this unit will be judged on: completeness (guaranteed to find a solution?), optimality (finds the best solution?), time complexity, and space complexity. These four properties appear on virtually every AI exam — learn them for every algorithm in this tutorial.

Problem-Solving Agents and Problem Formulation

Problem-Solving Agent

A problem-solving agent is a goal-based agent that plans ahead: it formulates a problem, searches for a solution sequence, and then executes that plan. Unlike a reflex agent (which reacts to each percept), it can consider multi-step futures.

Key assumption: the environment is static, fully observable, deterministic, and discrete. This makes planning tractable — the environment won't change while the agent thinks, and every action has a known, certain outcome.

The Five-Component Problem Formulation

Any problem to be solved by search is fully specified by five components. This is a commonly tested definition — memorise all five.

  1. Initial state s₀: Where the agent starts. e.g., In(Arad).
  2. Actions(s): Legal actions available in state s. e.g., {Go(Sibiu), Go(Zerind), Go(Timisoara)}.
  3. Transition model Result(s,a): The state resulting from taking action a in state s.
  4. Goal test Goal(s): Returns true when s is a goal. e.g., In(Bucharest).
  5. Path cost c(s,a,s'): Numeric cost of action a from s to s'. Total cost = sum of step costs along the path.

The state space is the set of all reachable states. It forms a directed graph — each node is a state, each edge is an action. Search algorithms explore this graph to find a goal.

Running Example Romania Road Map — Used Throughout This Tutorial

We use the classic Romania road problem (Russell & Norvig Ch. 3) as our running example. The agent starts in Arad and wants to reach Bucharest. Edge weights are road distances in km. The admissible heuristic h(n) = straight-line distance (SLD) to Bucharest.

City (n)Road Connections (km)h(n) = SLD to Bucharest
AradZerind 75 · Sibiu 140 · Timisoara 118366
ZerindArad 75 · Oradea 71374
SibiuArad 140 · Oradea 151 · RimnicuVilcea 80 · Fagaras 99253
TimisoaraArad 118 · Lugoj 111329
RimnicuVilceaSibiu 80 · Pitesti 97 · Craiova 146193
FagarasSibiu 99 · Bucharest 211178
PitestiRimnicuVilcea 97 · Craiova 138 · Bucharest 10198
Bucharest (GOAL)Fagaras 211 · Pitesti 101 · Giurgiu 90 · Urziceni 850

Optimal solution: Arad → Sibiu → RimnicuVilcea → Pitesti → Bucharest = 418 km. Every algorithm in this tutorial is benchmarked against this answer.

Breadth-First Search (BFS)

BFS expands the shallowest unexpanded node first by using a FIFO queue as the frontier. Think of the search as a wave that expands outward level by level — all nodes at depth d are explored before any node at depth d+1.

BFS Complexity b = branching factor, d = depth of shallowest goal, m = maximum depth Time: O(b^(d+1)) — generates all nodes at depth d, plus their children Space: O(b^(d+1)) — entire frontier at depth d lives in memory simultaneously Complete: YES (if b is finite) Optimal: YES (when all step costs are equal; shallowest = fewest steps = cheapest)
ALGORITHM: Breadth-First Search
1

Create frontier = FIFO queue with the initial node. Create explored = empty set.

2

If frontier is empty → return failure.

3

Dequeue node n. Goal test: if Goal(n.state) → return solution path to n.

4

Add n.state to explored. For each action a: if Result(n,a) not in explored or frontier → enqueue child.

5

Go to Step 2.

BFS Expansion on Romania Map — Level by Level Arad ① g=0 Zerind ② g=75 Sibiu ③ g=140 Timisoara ④ g=118 Oradea Fagaras Rimnicu Vilcea Lugoj Pitesti Bucharest GOAL ✓ depth 0 depth 1 depth 2 depth 3 FIFO Queue State (BFS) Dequeue Arad ① → Enqueue: [Zerind, Sibiu, Timisoara] Dequeue Zerind ② → Enqueue: [..., Oradea] Dequeue Sibiu ③ → Enqueue: [..., Fagaras, RimnicuVilcea] Dequeue Timisoara ④ → Enqueue: [..., Lugoj] Steps ⑤–⑧: expand depth-2 cities… Pitesti, Bucharest added to frontier Dequeue Bucharest → GOAL TEST ✓ Path: Arad→Sibiu→Fagaras→Bucharest
Figure 1.1 — BFS expands nodes ①–⑨ level by level. Orange dashed path shows the solution BFS finds: Arad→Sibiu→Fagaras→Bucharest (3 edges = shallowest). Note: this is shallowest by edges, not shortest by distance — for that, use Uniform-Cost Search.

Depth-First Search (DFS)

DFS expands the deepest unexpanded node first using a LIFO stack. It plunges as far down one branch as possible before backtracking. The critical advantage over BFS is linear memory — DFS only needs to store the nodes on the current path plus their unexpanded siblings at each level.

DFS Complexity Time: O(b^m) — may explore entire tree if goal is deep or absent Space: O(b × m) — stores only the current path + siblings ← KEY ADVANTAGE Complete: NO (infinite-depth spaces; loops without explored set) Optimal: NO (first solution found may be very deep and costly)
Watch Out — DFS Incompleteness

DFS without cycle detection will loop forever on any cyclic state space. Even with an explored set, DFS is incomplete in infinite-depth spaces. Never state "DFS is complete" without these qualifications. The space advantage of DFS only matters when the solution exists and is reached before memory would fill anyway.

Uniform-Cost Search (UCS)

BFS finds the shallowest goal, but not the cheapest when step costs vary. Uniform-Cost Search (Dijkstra's algorithm) expands the node with the lowest path cost g(n) using a priority queue. It is optimal for any non-negative step costs.

UCS Complexity (where C* = optimal cost, ε = min step cost) Time: O(b^(1 + floor(C*/ε))) Space: O(b^(1 + floor(C*/ε))) Complete: YES (if step costs ≥ ε > 0) Optimal: YES (always finds minimum-cost solution) UCS on Romania: expands by g(n) order: Arad(0) → Zerind(75) → Sibiu(140) → Timisoara(118) → ... Final path: Arad→Sibiu→RimnicuVilcea→Pitesti→Bucharest = 418 km ✓
🎯 Quick Check: BFS finds the shallowest solution. If road distances vary (e.g., Arad→Sibiu=140 km but Arad→Zerind=75 km), which algorithm guarantees the minimum-cost path?
✅ Correct! BFS is optimal only for uniform step costs (all edges cost 1). When costs vary, BFS might find a shorter path (by hops) that is more expensive by distance. UCS expands nodes in order of cumulative cost g(n), so the first time a goal is dequeued, it is reached via the cheapest path. IDDFS is optimal only for uniform step costs (same restriction as BFS).
Section 02

Depth-Limited, Iterative Deepening & Bidirectional Search

Pure BFS exhausts memory on deep problems. Pure DFS wanders forever in infinite spaces. The ideal algorithm would combine BFS's completeness with DFS's memory efficiency. Three refinements move us toward that ideal: Depth-Limited Search caps DFS to prevent infinite loops, Iterative Deepening IDDFS achieves BFS completeness with DFS space, and Bidirectional Search halves the depth by searching from both ends simultaneously.

Depth-Limited Search (DLS)

Depth-Limited Search

DLS is DFS with a preset depth limit . Nodes at depth ℓ are treated as if they have no successors. This prevents infinite descent but introduces a new failure: if the goal is deeper than ℓ, DLS returns cutoff — "goal exists but not within ℓ steps."

DLS Complexity Time: O(b^ℓ) Space: O(b·ℓ) Complete: NO — fails if goal depth d > ℓ Optimal: NO Key choice: ℓ = diameter of state space (max useful depth)

Iterative Deepening DFS (IDDFS)

IDDFS elegantly resolves the depth-limit dilemma: try every possible depth limit from 0 upward. Run DLS(0), then DLS(1), then DLS(2), … stopping at the first depth that finds a solution. Yes, nodes are re-expanded — but the overhead is remarkably small.

ALGORITHM: Iterative Deepening DFS (IDDFS)
1

Set depth limit ℓ = 0.

2

Run DLS(ℓ). If result = solution → return it. If result = failure (no solution anywhere) → return failure.

3

If result = cutoff (goal may exist deeper) → set ℓ = ℓ + 1 → go to Step 2.

IDDFS Overhead — Why Re-expansion is Cheap Total nodes expanded by IDDFS (branching factor b, goal depth d): N = (d+1)b⁰ + d·b¹ + (d-1)·b² + … + 1·bᵈ For b=10, d=5: BFS = 111,111 nodes IDDFS = 123,456 nodes (only ~11% more!) Overhead factor = b/(b-1) ≈ 1.11 for b=10, 1.25 for b=4 This small constant overhead buys: complete + optimal + O(b·d) space
IDDFS Complexity Time: O(b^d) — same asymptotic as BFS Space: O(b · d) — linear, same as DFS ← BEST OF BOTH WORLDS Complete: YES Optimal: YES (uniform step costs)
IDDFS — DLS at Increasing Depth Limits Until Goal Found Iteration ℓ=0 A ① Limit 0 reached. No goal → cutoff. 1 node expanded. Iteration ℓ=1 A ① B ② C ③ Limit 1 reached. No goal → cutoff. Iteration ℓ=2 → GOAL FOUND ✓ A ① B ② C ⑦ D ③ E ⑥ G④ ← GOAL! IDDFS total: 1 + 3 + 7+… nodes; overhead ≈ b/(b−1) × DFS — typically 10–25% extra; worth it for completeness + O(bd) space
Figure 2.1 — IDDFS across three iterations. Each iteration re-expands earlier nodes, but because the bottom level dominates the count, the total overhead is only ~b/(b−1) times DFS — a small constant. IDDFS is the recommended uninformed algorithm for unknown-depth problems.

Bidirectional Search

Bidirectional Search

Run two simultaneous searches: forward from the start, backward from the goal. Halt when the two frontiers intersect. Assemble the solution by joining the two half-paths at the meeting node.

Bidirectional BFS — The Exponential Saving Time: O(b^(d/2)) vs O(b^d) for standard BFS Space: O(b^(d/2)) Example b=10, d=10: One-direction BFS: 10^10 = 10,000,000,000 nodes Bidirectional BFS: 2×10^5 = 200,000 nodes (50,000× fewer!)

Comparing All Uniform Strategies

This comparison table is among the most heavily tested in AI exams. Memorise the completeness, optimality, and complexity for every row.

StrategyComplete?Optimal?TimeSpaceFrontier Structure
BFS✅ Yes¹✅ Yes²O(b^(d+1))O(b^(d+1))FIFO Queue
Uniform-Cost (UCS)✅ Yes³✅ YesO(b^(C*/ε))O(b^(C*/ε))Priority Queue (g)
DFS❌ No❌ NoO(b^m)O(b·m)LIFO Stack
Depth-Limited❌ No⁴❌ NoO(b^ℓ)O(b·ℓ)LIFO Stack + limit
IDDFS✅ Yes✅ Yes²O(b^d)O(b·d)LIFO Stack
Bidirectional BFS✅ Yes✅ Yes²O(b^(d/2))O(b^(d/2))Two FIFO Queues

¹ if b finite; ² if all step costs equal; ³ if all costs ≥ ε>0; ⁴ complete if ℓ≥d

Exam Tip — The Gold Standard

IDDFS is the recommended uninformed algorithm whenever the solution depth is unknown. It achieves BFS completeness and optimality using only DFS-level O(b·d) memory. If asked "which uninformed strategy is best in practice?" → answer IDDFS.

🎯 Quick Check: For b=4, d=8, how many nodes does bidirectional BFS examine compared to standard BFS?
✅ Correct! Standard BFS: O(b^(d+1)) = 4^9 ≈ 262,144 nodes. Bidirectional: O(2·b^(d/2)) = 2×4^4 = 2×256 = 512 nodes. That is 262,144 / 512 = 512 times fewer. The exponential gap grows with d — this is the whole power of bidirectional search.
Section 03

Heuristic Search Strategies & A*

Uniform search strategies are reliable but blind — they treat every direction as equally promising. Knowing that Bucharest lies east of Arad should steer us away from roads heading west. Informed (heuristic) search uses a function h(n) — a cheap estimate of remaining cost — to guide the frontier toward the goal and avoid wasted exploration.

This section covers three informed strategies in order of sophistication: Greedy Best-First Search (fast but suboptimal), A* (optimal and complete), and memory-bounded variants (IDA*, SMA*) that scale A* to large state spaces.

Heuristic Function h(n)

h(n) = estimated cost of the cheapest path from state n to a goal. Two key properties govern its quality:

Admissible: h(n) ≤ h*(n) for all n — never overestimates the true cost. Required for A* optimality.

Consistent (monotone): h(n) ≤ c(n,a,n') + h(n') for every edge. This is the triangle inequality; consistency implies admissibility.

Best heuristics come from relaxed problems — remove one or more constraints. 8-puzzle: allow tiles to move anywhere (not just to the adjacent blank) → Manhattan distance h(n) = Σ(|Δrow| + |Δcol|). A tighter (higher) admissible heuristic always expands fewer nodes.

Greedy Best-First Search

Greedy Evaluation Function f(n) = h(n) ← heuristic only; actual cost g(n) completely ignored Complete: NO Optimal: NO Romania: Greedy picks Fagaras (h=178) → path 140+99+211 = 450 km ❌ Optimal is 418 km — Greedy is 7.7% worse

A* Search — Optimal and Complete

A* Search — f(n) = g(n) + h(n)

A* expands the node minimising f(n) = g(n) + h(n): actual cost already incurred g(n) plus admissible estimate of remaining cost h(n). The sum f(n) estimates total path cost through n.

A* Properties f(n) = g(n) + h(n) Complete: YES Optimal: YES (admissible h) Time/Space: O(b^d) — exponential worst case; much better with tight h
Worked Example A* on Romania Map — Full f=g+h Trace

Heuristic: h(n) = SLD to Bucharest (admissible because road ≥ straight-line always).

StepExpandedg(n)h(n)f=g+hNext frontier (by f)
1Arad0366366Sibiu(393), Timisoara(447), Zerind(449)
2Sibiu140253393RimnicuVilcea(413), Fagaras(415)…
3RimnicuVilcea220193413Fagaras(415), Pitesti(417)…
4Fagaras239178417Pitesti(417), Bucharest-via-Fagaras(450)…
5Pitesti31798417Bucharest-via-Pitesti(418)!, …
6Bucharest4180418 ✓Optimal path found!
Final Answer

Optimal: Arad(0)→Sibiu(140)→RimnicuVilcea(220)→Pitesti(317)→Bucharest(418 km). A* rejects Fagaras→Bucharest (total 450 km) because it tracks g(n). Only 6 nodes expanded to find the global optimum.

Memory-Bounded Heuristic Search

IDA* (Iterative Deepening A*)
f-limit iterations
Iterative deepening on f-value instead of depth. Each pass expands nodes with f(n) ≤ threshold; threshold grows to minimum f that exceeded cutoff. Space: O(bd). Complete and optimal. Best for memory-limited problems with admissible h.
SMA* (Simplified Memory-Bounded A*)
Drop worst leaf when full
Uses all available memory M. When full, drops the leaf with the highest f-value and backs its f up to its parent. Complete if the optimal solution path fits in M nodes. Optimal when memory allows.
Heuristic Dominance
h₂ ≥ h₁ → h₂ dominates
A tighter admissible heuristic always expands fewer nodes. 8-puzzle: Manhattan (h₂) dominates Misplaced Tiles (h₁) — h₂(n) ≥ h₁(n) always. Use max(h₁,h₂) when you have multiple admissible heuristics.
Weighted A* Trade-off
f(n) = g(n) + w·h(n), w>1
Deliberately overweight h to expand fewer nodes, trading optimality for speed. Solution cost ≤ w × C*. Controls speed/quality: w=1 = standard A*; w=∞ = Greedy Best-First.
Classic Example Admissible Heuristics for the 8-Puzzle — Dominance Check

State: [[7,2,4],[5,_,6],[8,3,1]], Goal: [[1,2,3],[4,5,6],[7,8,_]]

TileCurrent (r,c)Goal (r,c)Misplaced?Manhattan dist
1(2,2)(0,0)4
2(0,1)(0,1)✓ In place0
3(2,1)(0,2)3
4(0,2)(1,0)3
5(1,0)(1,1)1
6(1,2)(1,2)✓ In place0
7(0,0)(2,0)2
8(2,0)(2,1)1
Totalsh₁ = 6h₂ = 14 (dominates!)

Manhattan distance h₂=14 provides a much tighter lower bound than h₁=6. A* with h₂ expands approximately 32× fewer nodes than A* with h₁ at depth 14.

🎯 Quick Check: A* with an inadmissible heuristic (one that sometimes overestimates h*) is guaranteed to:
✅ Correct! Admissibility (h(n) ≤ h*(n)) is the requirement for A* optimality. If h overestimates, A* may assign f(n) > C* to an optimal-path node and skip it, returning a more expensive solution instead. Intentional overweighting (Weighted A*, f = g + w·h, w>1) is used as a controlled speed/quality tradeoff — it guarantees solution cost ≤ w × C*.
Section 04

Local Search & Optimisation

All algorithms so far maintain a complete path from start to goal. But many real problems — factory scheduling, protein folding, microchip layout — only care about the final configuration. Their state spaces are too vast for systematic exploration. Local search keeps only the current state and moves to neighbouring states to improve an objective function, using almost no memory. The trade-off: most landscapes have many local peaks that are not the global optimum.

Objective Function Landscape — Core Challenge of Local Search Local max Global max ★ local min agent Hill climb → local max SA / GA escape to global max plateau
Figure 4.1 — Objective function landscape. Hill climbing (orange) gets stuck at the local maximum. Simulated Annealing and Genetic Algorithms (green dashed) escape via controlled randomness and reach the global maximum (★).

Hill Climbing (Steepest Ascent)

ALGORITHM: Hill Climbing — Steepest Ascent
1

Set current = initial state.

2

Compute best_neighbour = highest-valued neighbour of current.

3

If VALUE(best_neighbour) ≤ VALUE(current) → return current (local maximum). Else set current = best_neighbour → go to Step 2.

Three Failure Modes of Hill Climbing

Local maxima: Better than all neighbours but not global best — halts prematurely.
Ridges: Sequence of local maxima forming a ridge — diagonal moves needed to traverse.
Plateaus: All neighbours have equal value — random sideways moves needed to escape.

Worked Example Hill Climbing on 8-Queens — Minimise h = attacking pairs
IterationMoveh (attacking pairs)Status
StartRandom placement17Initialise
1Move col-3 queen: row 4 → row 112↓ Improved
2Move col-6 queen: row 7 → row 37↓ Improved
3Move col-2 queen: row 5 → row 24↓ Improved
4No single move reduces h below 44Local min — STUCK
RestartNew random start → hill climb0Goal found! ✓

86% of random starts reach a local min. Random-restart hill climbing succeeds after ≈ 7 restarts on average. Success after k restarts = 1 − 0.86^k → very reliable.

Simulated Annealing

ALGORITHM: Simulated Annealing (Kirkpatrick et al., 1983)
1

Set current = initial state; temperature T = T₀ (high).

2

Pick a random neighbour next. Compute ΔE = VALUE(next) − VALUE(current).

3

If ΔE > 0 → accept. If ΔE ≤ 0 → accept with probability P = e^(ΔE/T).

4

Cool: T = α·T (e.g. α=0.99). If T ≈ 0 → return current. Else go to Step 2.

SA Acceptance Probability P = e^(ΔE / T) ΔE = −5: T=1000 → P≈0.995 (explore widely) T=10 → P≈0.607 T=1 → P≈0.007 (nearly hill climbing) T→0 → P→0 (pure hill climbing)

Local Beam Search & Genetic Algorithms

Local Beam Search

Maintain k states simultaneously. Generate all successors of all k states; keep the k best. Unlike k independent hill climbs, beams share information — successful beams attract others. Stochastic beam search selects k survivors probabilistically (∝ VALUE) to avoid all k converging on the same local max.

ALGORITHM: Genetic Algorithm (Holland, 1975) — Overview
1

Initialise: k random individuals (encoded strings). Evaluate fitness f(x).

2

Select: Pairs of parents proportional to fitness (roulette wheel). Higher fitness = higher reproduction chance.

3

Crossover: Swap tails at a random cut-point to produce two children. e.g. 11010|001 + 00110|11111010|111 and 00110|001.

4

Mutate: Flip each bit with small probability p_m ≈ 0.01 — maintains diversity.

5

Replace & repeat until termination criterion (max generations or sufficient fitness).

AlgorithmMemoryEscapes Local Optima?Optimal?Best Application
Hill ClimbingO(1)❌ No❌ NoQuick; use with random restarts
Simulated AnnealingO(1)✅ Yes (probabilistic)✅ Slow coolingTSP, VLSI layout, scheduling
Local Beam SearchO(k·b)✅ Partially❌ Nok parallel searches sharing info
Genetic AlgorithmsO(population)✅ Yes (crossover)❌ No (practice)Design optimisation, feature selection
🎯 Quick Check: In Simulated Annealing, as temperature T decreases toward 0, the probability of accepting a worse state:
✅ Correct! P = e^(ΔE/T). As T→0 with ΔE < 0: ΔE/T → −∞, so e^(ΔE/T) → 0. No worse moves are accepted — the algorithm becomes steepest-ascent hill climbing. This controlled transition from wide exploration at high T to pure exploitation at T≈0 is exactly what allows SA to escape local optima and converge to the global optimum given a sufficiently slow cooling schedule.
Section 05

Constraint Satisfaction Problems

Standard search treats states as black boxes with no internal structure. Constraint Satisfaction Problems (CSPs) exploit that structure: each state is an assignment of values to variables, and solutions must satisfy a set of constraints. This enables constraint propagation — reasoning that prunes impossible values before search even begins — making exponential problems tractable in practice.

CSPs arise everywhere: Sudoku (variables=cells, domains=1–9, constraints=no row/col/box repeats), map colouring, timetabling, circuit layout, frequency assignment, and crossword puzzles.

Constraint Satisfaction Problem — Formal Definition

A CSP has three elements:

  1. Variables X = {X₁ … Xₙ}: What we must assign values to.
  2. Domains D = {D₁ … Dₙ}: Set of legal values for each variable.
  3. Constraints C: Relations restricting which value combinations are legal.

Solution = a complete (all variables assigned) and consistent (no constraint violated) assignment.

Classic Example Australia Map Colouring — Full CSP Formulation

Colour 7 Australian regions so no two adjacent regions share a colour, using {Red, Green, Blue}.

VariableDomainNeighbours (≠ constraints with)Degree (# constraints)
WA{R,G,B}NT, SA2
NT{R,G,B}WA, SA, Q3
Q{R,G,B}NT, SA, NSW3
SA{R,G,B}WA, NT, Q, NSW, V, T6 — assign FIRST (MRV)
NSW{R,G,B}Q, SA, V3
V{R,G,B}SA, NSW2
T{R,G,B}None (island)0 — assign anytime

Valid solution: WA=Red, NT=Green, Q=Red, SA=Blue, NSW=Green, V=Red, T=Green. SA is assigned first (most constrained — 6 neighbours restrict its choices most).

Backtracking Search for CSPs

ALGORITHM: Backtracking Search for CSP (with MRV + LCV + Forward Checking)
1

If all variables assigned → return assignment (success).

2

Select unassigned variable X by MRV (fewest remaining legal values — "fail first").

3

Order values in DOMAIN(X) by LCV (least constraining value — rules out fewest neighbour values).

4

For each value v: if X=v is consistent → assign it. Apply forward checking: remove v from neighbours' domains. If any domain empties → undo, try next v.

5

Recurse. If success → return. Else remove X=v and try next. If all values fail → return failure (backtrack).

Local Search for CSPs — Min-Conflicts

Min-Conflicts Heuristic

Start with a complete but possibly inconsistent assignment. Repeatedly select a conflicted variable and reassign it to the value minimising the number of violated constraints. Halt when no conflicts remain.

For N-Queens: solves N=1,000,000 in roughly the same number of steps as N=100 — essentially constant in N. This is one of the most striking results in local search for CSPs.

MRV Heuristic
min |domain(X)|
"Fail-first": assign the most constrained variable first to detect failures early and prune large subtrees before more variables are committed.
Degree Heuristic
max constraints on X
Tiebreaker for MRV. Pick the variable involved in the most constraints on remaining unassigned variables. Also "fail-first" in spirit.
LCV Heuristic
min domain-eliminations
"Fail-last" for values: choose the value that rules out fewest choices for neighbours. Leaves maximum future flexibility for subsequent assignments.
Arc Consistency (AC-3)
∀(X,Y): D(X) pruned
For every arc (X→Y), remove values from D(X) with no consistent value in D(Y). Stronger than forward checking. O(e·d³) time. Often reduces domains dramatically before search begins.
🎯 Quick Check: In backtracking CSP search, MRV selects the most constrained variable. This "fail-first" strategy is beneficial because:
✅ Correct! "Fail-first" means: if a branch is going to fail, discover it with as few committed variables as possible. By assigning the most constrained variable first (fewest remaining legal values), any inconsistency is detected before many other variables have been assigned — pruning the entire subtree below that conflict immediately. Counter-intuitively, assigning the hardest variable first leads to faster overall search.
Section 06

Adversarial Search & Game Playing

Until now the environment was benign — static or merely stochastic. Games introduce a rational adversary who actively minimises our utility. A move that looks excellent may be catastrophic if the opponent responds optimally. Adversarial search provides the mathematical framework for reasoning under strategic opposition.

Two-Player Zero-Sum Perfect-Information Game

Defined by: S₀ (initial state), PLAYER(s) (MAX or MIN), ACTIONS(s), RESULT(s,a), TERMINAL-TEST(s), UTILITY(s,p): +1 win / 0 draw / −1 loss for player p. Zero-sum: what MAX gains, MIN loses. Both play perfectly rational.

The Minimax Algorithm

ALGORITHM: Minimax (Von Neumann 1928 / Shannon 1950)
1

If TERMINAL-TEST(s) → return UTILITY(s).

2

If PLAYER(s) = MAX → return max over a of MINIMAX(RESULT(s,a)).

3

If PLAYER(s) = MIN → return min over a of MINIMAX(RESULT(s,a)).

Minimax Complexity Time: O(b^m) Space: O(b·m) Complete: YES Optimal: YES vs optimal opponent Chess: b≈35, m≈100 → 35^100 ≈ 10^154 — complete search impossible Solution: depth-limited + evaluation function EVAL(s) for non-terminal states
Worked Example Minimax Trace — 3-Ply Game Tree with Leaf Values
3 5 2 9 1 6 4 7 5 6 9 7 MIN=2 2 MIN=1 1 MIN=4 4 MIN=5 5 MIN=6 6 MIN=7 7 MAX=2 2 MAX=5 5 MAX=7 7 MIN(root)=2 2 d=0 MIN d=1 MAX d=2 MIN d=3 leaf
Figure 6.1 — Minimax 3-ply tree. Leaves propagate up: MIN takes minimum, MAX takes maximum. Root (MIN) returns 2. Orange path shows the chosen branch.

Alpha-Beta Pruning

Alpha-Beta Pruning — Two Bounds

α = best value MAX has guaranteed so far (init −∞). Updated at MAX nodes.
β = best value MIN has guaranteed so far (init +∞). Updated at MIN nodes.
Prune at MAX node: if value ≥ β → cut (MIN won't allow this).
Prune at MIN node: if value ≤ α → cut (MAX has better elsewhere).

Alpha-Beta Complexity Best case (perfect ordering): O(b^(m/2)) — doubles searchable depth! Average: O(b^(3m/4)) Worst: O(b^m) — no pruning Chess b=35, m=8: Full minimax: 35^8 ≈ 2.25 trillion nodes α-β best: 35^4 ≈ 1.5 million nodes → 1.5M times fewer!

Additional Refinements

Evaluation Function
EVAL(s) ≈ UTILITY(s)
Heuristic estimate of state value for non-terminal states at the depth cutoff. Chess: weighted sum of material balance, mobility, king safety, pawn structure. Must be fast and correlated with winning probability.
Quiescence Search
Extend on non-quiet positions
Continue searching beyond depth limit when the position is volatile (captures, checks). Prevents the "horizon effect" — calling EVAL on positions where a decisive move lurks just out of sight.
Move Ordering
Best moves first
Alpha-beta achieves O(b^(m/2)) only with good move ordering. Heuristics: try captures first, killer moves (caused cutoff in sibling), history table. Better ordering = more pruning.
Iterative Deepening (Games)
depth 1, 2, 3… till time
Run alpha-beta to depth 1, then 2, then 3… until time budget runs out. Always has a best move ready. Previous iteration informs move ordering for next. Used in all serious chess engines.
Note — Modern Game AI: AlphaZero

Traditional engines (Deep Blue, Stockfish) use handcrafted EVAL + alpha-beta + iterative deepening. AlphaZero (2017) replaced EVAL with a deep neural network trained by self-play and replaced alpha-beta with Monte Carlo Tree Search (MCTS). It beat world-champion engines in chess, Go, and Shogi after hours of self-play. Yet the core principle — search guided by value estimates — is unchanged since Shannon 1950.

🎯 Quick Check: Alpha-beta with perfect move ordering gives O(b^(m/2)). For b=35 and m=8, approximately how many times fewer nodes does alpha-beta examine than full minimax?
✅ Correct! Full minimax: 35^8 ≈ 2.25×10^12. Alpha-beta best case: 35^4 ≈ 1.5×10^6. Ratio: 2.25T / 1.5M ≈ 1.5 million times fewer nodes. This is the difference between "cannot finish in the lifetime of the universe" and "runs in milliseconds." With realistic (imperfect) ordering, the improvement is about 35^6 ≈ 10^9 — still over a billion times fewer than full minimax.
Section 07

Exam Preparation Summary

This section consolidates every algorithm, formula, and comparison from Unit II. Work through all tables and the final challenge quiz before your exam.

Master Algorithm Comparison

AlgorithmComplete?Optimal?TimeSpaceKey Idea
BFS✅ Yes¹✅ Yes²O(b^(d+1))O(b^(d+1))FIFO; shallowest first
Uniform-Cost✅ Yes³✅ YesO(b^(C*/ε))O(b^(C*/ε))Priority queue by g; cheapest first
DFS❌ No❌ NoO(b^m)O(b·m)LIFO; deep first; low memory
Depth-Limited❌ No⁴❌ NoO(b^ℓ)O(b·ℓ)DFS with cap ℓ
IDDFS ★✅ Yes✅ Yes²O(b^d)O(b·d)Best uninformed: BFS quality + DFS space
Bidirectional✅ Yes✅ Yes²O(b^(d/2))O(b^(d/2))Two frontiers meet in middle
Greedy Best-First❌ No❌ NoO(b^m)O(b^m)Priority by h only; fast, suboptimal
A* ★✅ Yes✅ Yes (adm. h)O(b^d)O(b^d)f=g+h; best informed; complete + optimal
IDA*✅ Yes✅ YesO(b^d)O(b·d)A* with DFS-level memory
Hill Climbing❌ No❌ NoO(1)Greedy local; stuck at local optima
Simulated Annealing✅ Yes⁵✅ Yes⁵O(1)P=e^(ΔE/T) acceptance; escapes optima
Local Beam❌ No❌ NoO(k·b)k parallel states sharing info
Genetic Algorithm❌ No❌ NoO(pop)Selection + crossover + mutation
Backtracking CSP✅ YesN/AO(n·d)DFS + constraint check + backtrack
Minimax✅ Yes✅ YesO(b^m)O(b·m)Max/min alternating; game trees
Alpha-Beta ★✅ Yes✅ YesO(b^(m/2)) bestO(b·m)Minimax + pruning; same result, fewer nodes

¹ b finite; ² uniform cost; ³ costs≥ε>0; ⁴ yes if ℓ≥d; ⁵ logarithmic cooling schedule; ★ = recommended for each category

Key Formulas

FormulaMeaningUsed In
f(n) = h(n)Heuristic only; ignores g(n)Greedy Best-First
f(n) = g(n) + h(n)Actual + estimated remaining costA*, IDA*
h(n) ≤ h*(n) ∀nAdmissibility — never overestimateA* optimality proof
h(n) ≤ c(n,a,n') + h(n')Consistency (triangle inequality)A* no re-expansion
P = e^(ΔE/T)SA acceptance probability for worse stateSimulated Annealing
V(MAX node) = max_a V(child)MAX picks highest childMinimax
V(MIN node) = min_a V(child)MIN picks lowest childMinimax
O(b^(d/2))Alpha-beta best case; doubles searchable depthAlpha-Beta

Common Exam Mistakes

Watch Out!

Mistake 1: Calling DFS "complete" — NOT complete in infinite-depth or cyclic spaces.

Mistake 2: Saying BFS is optimal for weighted graphs — only optimal for uniform step costs. Use UCS for varying costs.

Mistake 3: Confusing admissibility and consistency — consistency is stronger; consistent ⟹ admissible, not vice versa.

Mistake 4: Saying alpha-beta finds a better solution than minimax — it finds the same solution faster by pruning irrelevant branches.

Mistake 5: Confusing MRV (which variable next in CSP) with LCV (which value to try next) — different decisions, different heuristics.

Mistake 6: Saying SA is always globally optimal — only with a logarithmically slow cooling schedule (impractically slow). In practice it finds near-optimal solutions.

One-Line Summaries

Best Uninformed
IDDFS
BFS completeness + optimality + DFS O(bd) space. Overhead ≈ b/(b−1): negligible.
Best Informed
A*
Optimal + complete with admissible h. Memory bottleneck → IDA* for space-limited settings.
Optimisation
Sim. Annealing
O(1) memory. Escapes local optima via P=e^(ΔE/T). Best for TSP, scheduling, layout.
CSP Solver
MRV + FC + AC-3
Fail-first variable selection + forward checking + arc consistency = tractable CSP solving.
Game Playing
Alpha-Beta
Minimax result at O(b^(m/2)) vs O(b^m). Move ordering is critical for full benefit.
Bidirectional
O(b^(d/2))
Exponential saving vs one-directional BFS for long paths. Two frontiers meet in middle.

Challenge Quiz

🎯 Challenge: A factory scheduling AI must assign 50 jobs to machines. A* runs out of memory. Hill climbing gets stuck at suboptimal schedules. Which approach would you recommend?
✅ Correct! This is a classic two-phase approach. Phase 1 (feasibility): IDA* finds a feasible schedule (satisfying hard constraints like deadlines) using only O(b·d) memory — unlike A* which exhausted memory, or BFS which cannot scale to 50 variables. Phase 2 (optimisation): Simulated Annealing improves the feasible solution (minimise makespan or cost) — it uses O(1) memory, escapes the local optima that trapped hill climbing, and handles the astronomically large optimisation landscape. CSP backtracking with MRV + FC is also excellent for Phase 1 when constraints are dense.