Hard to Find, Easy to Check
In short: every algorithm this course has taught so far runs in time that is a polynomial in its input size — that's the class P. Finding the cheapest tour through a handful of stops isn't known to have any such algorithm: the best general method is still brute force over every ordering, and the number of orderings explodes factorially. But checking a tour someone else hands you — does it visit every stop once, does it cost what they claim — takes barely any work at all. That gap, between finding a solution and checking one, is what the class NP names, and it's not a philosophical point: you can measure it on your own laptop.

Count what brute force actually tries
Meridian's bid desk gets a tender with a handful of stops and needs the cheapest loop that visits every one of them and returns to the start. There's no shortcut known: try every ordering, score each one, keep the best.
Four stops means 3! = 6 orderings — nothing. The start city never moves, so
what grows is (n - 1)!, the orderings of everyone else. This is never about
how fast your machine is: doubling the clock speed buys you maybe one more
stop before the wait becomes a problem again, because the count itself is
growing factorially, not the time per step.
import math
def permutations_to_try(n):
return math.factorial(n - 1) if n >= 1 else 1
print([permutations_to_try(n) for n in (4, 8, 12)])Checking a tour is a different kind of work entirely
Say a bidder hands Meridian a proposed route and claims it costs ₹18,000. Checking that claim doesn't need any ordering to be tried — just a single walk through the route they already gave you:
verify_tour is a sort and a comparison: O(n log n). route_cost is one
pass: O(n). Neither one searches anything — there is nothing to search,
because the route to check is already in your hand. That asymmetry, not wall
clock seconds (your laptop's clock speed changes; the number of checks for a
given n does not), is what separates P (verify_tour, route_cost —
solvable and checkable fast) from the harder class a brute-force tour
search sits in.
This prints (True, 3), missing the length check. Make it print (True, 4).
Quick practice
import math
print(math.factorial(5), math.factorial(5 - 1))def verify_checks(n):
return n + 1
print(verify_checks(12), verify_checks(1000))🎯 Your turn
Build bid_desk_tsp(cities, edges). cities is a list of stop names;
edges is [a, b, cost] covering every pair. Fix cities[0] as the start,
try every ordering of the rest, and return the cheapest loop as
{"route": ..., "cost": ..., "permutations_tried": ...}. A single city needs
no permutations at all: {"route": cities, "cost": 0, "permutations_tried": 1}.
bid_desk_tsp(["a", "b", "c"], [["a","b",1],["b","c",1],["a","c",5]])→ cost7,2permutations tried.
Hint: itertools.permutations(cities[1:]) gives every ordering of
everyone except the start; score each one and keep the cheapest.
Press ▶ Run, try the Live App chips, then ✓ Check.
