Parameterised Complexity and FPT

"NP-hard" measures difficulty against a single yardstick: the input size n. But that yardstick is crude. Two instances of the same size can be worlds apart in difficulty, and the thing that makes one easy is often some second quantity — the size of the solution you're looking for, how tree-like the graph is, how many constraints you'd need to delete. Parameterised complexity, launched by Downey and Fellows, is the theory that takes that second quantity seriously. It is the sharpest tool in the coping kit for problems where a natural parameter stays small.

The payoff is a running time like 2^k \cdot n: exponential, yes — but the explosion is confined to the small parameter k, while the large quantity n enters only polynomially. When k=20 and n = 10^7, that is the difference between an answer over lunch and the heat death of the universe.

FPT versus XP: where the parameter sits

A parameterised problem attaches a parameter k to each input of size n. Two very different notions of "efficient" arise, and the whole subject turns on the difference:

The distinction is everything. n^k with k = 20 and n = 10^6 is 10^{120} — hopeless. But 2^k n = 2^{20}\cdot 10^6 \approx 10^{12} — a few minutes. FPT keeps k and n in separate factors; XP lets k climb into n's exponent, where it does ruinous damage. Every parameterised algorithm designer is trying to move a problem from XP down into FPT.

Vertex Cover is FPT: a bounded search tree

The decision question "is there a vertex cover of size \le k?" is FPT by a gorgeous argument. Take any edge (u,v): every cover must contain u or v. So branch — recurse twice, once putting u in the cover, once v — and in each branch the budget drops by one.

// Is there a vertex cover of size ≤ k? Runs in O(2^k · n) time. function vcFPT(edges: [number, number][], k: number): boolean { if (edges.length === 0) return true; // everything covered if (k === 0) return false; // budget spent, edges remain const [u, v] = edges[0]; // pick any uncovered edge const without = (x: number) => edges.filter(([a, b]) => a !== x && b !== x); return vcFPT(without(u), k - 1) // branch 1: take u || vcFPT(without(v), k - 1); // branch 2: take v }

The recursion tree has depth at most k and branches two ways, so it has at most 2^k leaves, and each node does O(n) work: total O(2^k n). The exponential is nailed to k; n is merely linear. The figure grows this search tree level by level — watch the leaf count double each time, capped at 2^k no matter how large the graph.

Clever branching does even better — analysing high-degree vertices first drives the base below 2, to around 1.28^k. But the shape is the point: a search tree whose size is a function of k only.

Kernelisation: shrink the instance first

The second pillar of FPT is kernelisation — polynomial-time preprocessing that provably shrinks an instance down to a size bounded by a function of k alone (the kernel), after which even brute force is fast. A theorem ties it all together: a problem is FPT if and only if it has a kernel.

You are left with a \le 2k-vertex kernel independent of the original n — solve that however you like. Kernelisation is why FPT algorithms are fast in practice as well as theory: the expensive step runs on a tiny residue.

Treewidth, and the "not-FPT" frontier: W[1]-hardness

Treewidth measures how close a graph is to a tree; a width-w tree decomposition lets dynamic programming sweep the graph solving countless NP-hard problems in 2^{O(w)}\cdot n time — FPT parameterised by treewidth. Bounded treewidth is one of the most fruitful parameters in the whole theory: real inputs (control-flow graphs, series-parallel networks) often have small width.

But not everything is FPT. Just as NP-completeness marks the likely-intractable decision problems, W[1]-hardness marks the likely-not-FPT parameterised problems. The canonical W[1]-complete problem is Clique parameterised by clique size k: the best known algorithms are essentially n^{O(k)} (XP, not FPT), and a W[1]-hardness proof is strong evidence no f(k)\cdot n^{O(1)} algorithm exists. So Vertex Cover (FPT) and Clique (W[1]-hard) — near-identical-looking problems, one the complement of the other — sit on opposite sides of the tractability line. Parameterised complexity is exactly the lens that can tell them apart.

They are complementary: S is a vertex cover iff its complement is an independent set, and a clique in a graph is an independent set in the complement graph. So why the chasm? Because the parameter behaves differently. A vertex cover of size k is a small object whose choice is forced edge by edge — branching shrinks k each step. A clique of size k gives you no such local handle; finding it seems to require examining k-tuples, and the parameter refuses to detach from n's exponent. The moral: FPT-ness is a property of the problem-plus-parameter, not the raw problem — pick a different parameter and tractability can flip.

The most common beginner error is to see a running time of n^k, note that "for any fixed k this is polynomial," and declare victory. It is not FPT — it is XP, and it is usually useless. The degree of the polynomial grows with k, so the algorithm dies the moment k is more than a handful: n^{10} on a million-node graph is 10^{60} operations. FPT demands that k and n live in separate factors — f(k)\cdot n^{c} with c a constant independent of k. If you can't get k out of the exponent of n, you don't have an FPT algorithm.