A Tour of Classic NP-Complete Problems

Suppose an airline scheduler needs to assign crews to flights. No two conflicting shifts can overlap. Every route must be covered with a bounded number of crews. This looks nothing like a Boolean satisfiability puzzle. Yet underneath, both problems share an identical combinatorial skeleton. The remarkable discovery at the heart of this article is this: thousands of problems arising in scheduling, network design, computational biology, and logistics are secretly the same problem. They are simply dressed in different clothing. Once NP-Completeness and Cook-Levin establishes that some canonical problem — Boolean satisfiability — is as hard as anything whose solutions can be efficiently checked, the next order of business is to build a web of reductions. This web connects that seed problem to a broad catalogue of others. This is not a bureaucratic exercise. When an engineer recognizes that their new scheduling puzzle reduces from Vertex Cover, they instantly inherit decades of hardness knowledge. More importantly, they gain a toolbox of known approximation and heuristic strategies. Recognizing NP-completeness saves enormous wasted effort. It stops engineers trying to find an exact polynomial algorithm that provably cannot exist (unless P = NP). This article walks through the classic reduction chain. It transforms 3-SAT into Clique, then into Vertex Cover and Independent Set. Separately, it builds Hamiltonian Cycle and the Traveling Salesman Problem. It also builds Subset-Sum, all via Polynomial-Time Reductions. Each reduction is a small piece of engineering. It is a gadget that faithfully encodes the logical structure of one problem inside the combinatorial structure of another. Seeing several of these gadgets side by side reveals a set of recurring reduction idioms. These include variable gadgets, clause gadgets, and path-forcing gadgets. They reappear across the entire theory of computational hardness. By the end, the reader will have more than just a list of "problems that are NP-complete." They will have a working mental model of why they are all secretly related. They will also gain the constructive skill to build a reduction for a brand-new problem. This sets up naturally for Coping with NP-Hardness and Approximation Algorithms and the Approximation Ratio. There, we ask what to do once a problem has been proven hard.

Key takeaways
  • NP-completeness is established for one problem (via Cook–Levin) and then spread through polynomial-time reductions to many others.
  • 3-SAT reduces to Clique via a gadget where each literal occurrence becomes a graph node, connected across non-conflicting clauses.
  • Clique, Vertex Cover, and Independent Set are trivially interreducible via simple complement/dual transformations on the same graph.
  • Hamiltonian Cycle reduces from 3-SAT using variable "gadget" cycles and clause-satisfaction connector nodes; TSP then reduces from Hamiltonian Cycle by weighting edges 1 or 2.
  • Subset-Sum is NP-complete via a reduction from Vertex Cover (or directly from 3-SAT), and it is the ancestor of many "packing" and "knapsack" style problems.
  • All these results assume P ≠ NP; the value of the theory lies in constructive reductions, not just abstract classification.
The core insight

Every NP-complete problem is joined to every other by an explicit polynomial-time gadget reduction, so proving hardness for one instantly proves it for the entire web.

The idea

A problem LL is NP-complete if L∈NPL \in \mathrm{NP} and every problem in NP polynomial-time reduces to LL. The Cook–Levin theorem gives the seed: Boolean satisfiability (SAT), and its restricted variant 3-SAT (formulas in conjunctive normal form with exactly three literals per clause), is NP-complete because a nondeterministic Turing machine's computation history can be encoded as a Boolean formula whose satisfying assignments correspond exactly to accepting computations. Once one NP-complete problem L1L_1 is known, a new problem L2∈NPL_2 \in \mathrm{NP} is proven NP-complete by exhibiting a polynomial-time reduction L1≤pL2L_1 \le_p L_2: a function ff, computable in polynomial time, such that x∈L1  ⟺  f(x)∈L2x \in L_1 \iff f(x) \in L_2. Because polynomial-time reductions compose (if L1≤pL2L_1 \le_p L_2 and L2≤pL3L_2 \le_p L_3 then L1≤pL3L_1 \le_p L_3), and because every problem in NP already reduces to L1L_1, transitivity forces every problem in NP to reduce to L2L_2 as well. This is the mechanism by which NP-completeness "spreads" — a single reduction step attaches an entire new problem to the growing web rooted at SAT. The art of proving NP-completeness is almost entirely the art of designing gadgets: small, local pieces of structure that simulate one combinatorial primitive (a Boolean variable, a clause, a choice) inside the target problem's native language (a graph edge, a weighted arc, a subset sum). A gadget must satisfy two properties simultaneously — completeness (a "yes" instance of the source maps to a "yes" instance of the target) and soundness (a "yes" instance of the target can be decoded back into a "yes" instance of the source). Getting both directions right, with only polynomially many gadget copies and polynomial-time construction, is the technical heart of every reduction in this article.

How it works

We build the reduction web in stages, each stage reusing structure from the previous one.

Stage 1: 3-SAT to Clique. Given a 3-CNF formula φ\varphi with kk clauses C1,…,CkC_1, \dots, C_k, each containing (up to) three literals, construct a graph GG as follows. For each clause CiC_i, create one node for each literal occurrence in that clause (so at most 3k3k nodes total, grouped into kk "clause groups"). Draw an edge between two nodes in different clause groups if and only if their literals are consistent — that is, they are not negations of each other (e.g., x3x_3 and ¬x3\lnot x_3 get no edge, but x3x_3 and x3x_3, or x3x_3 and x7x_7, do get an edge). No edges are drawn within a clause group. The claim: φ\varphi is satisfiable if and only if GG has a clique of size kk.

Stage 2: Clique, Vertex Cover, Independent Set — the graph-complement triangle. These three are almost the same problem viewed from different angles. In a graph G=(V,E)G = (V, E) with ∣V∣=n|V| = n:

  • S⊆VS \subseteq V is a clique iff every pair in SS is connected by an edge.
  • SS is an independent set iff no pair in SS is connected by an edge.
  • SS is a vertex cover iff every edge has at least one endpoint in SS.

The identity linking independent sets and vertex covers: SS is an independent set of GG if and only if V∖SV \setminus S is a vertex cover of GG. And SS is a clique in GG if and only if SS is an independent set in the complement graph Gˉ\bar G (where edges and non-edges are swapped). These are constant-time (well, O(n2)O(n^2) to build Gˉ\bar G) reductions, so Clique, Independent Set, and Vertex Cover are all NP-complete together once one of them is shown hard.

Stage 3: 3-SAT to Hamiltonian Cycle. This reduction is more intricate. For each Boolean variable xix_i, build a variable gadget: a chain of diamond-shaped node clusters that can be traversed left-to-right or right-to-left, corresponding to setting xix_i true or false. For each clause CjC_j, add a clause node connected to the variable gadgets of the literals it contains, positioned so that a Hamiltonian cycle can "detour" through the clause node only if at least one of its literals is set consistently with the traversal direction chosen for that variable. Chaining all variable gadgets in sequence and attaching clause nodes as controlled side-trips produces a graph with a Hamiltonian cycle if and only if φ\varphi is satisfiable.

Stage 4: Hamiltonian Cycle to TSP. Given a graph G=(V,E)G = (V, E) for Hamiltonian Cycle, build a complete weighted graph KnK_n on the same vertex set: edges present in GG get weight 1, and all other (added) edges get weight 2. Set the budget B=nB = n (the number of vertices). Then GG has a Hamiltonian cycle if and only if KnK_n has a tour of total weight ≤B\le B — because any tour must use exactly nn edges, and it can only achieve weight nn if every edge used has weight 1, i.e., every edge belongs to the original graph GG.

Stage 5: 3-SAT (or Vertex Cover) to Subset-Sum. We reduce from Vertex Cover on a graph G=(V,E)G=(V,E) with ∣V∣=n|V|=n, ∣E∣=m|E|=m, target cover size kk. Assign each vertex viv_i a number and each edge eje_j a number, all written in base 10 (or any base ≥4\ge 4) with n+mn + m digits, so that different structural roles never carry over into each other's digit columns. Concretely: vertex viv_i contributes a 1 in digit position ii (from a block of nn vertex-columns) and a 1 in the digit position of every edge column it touches; edge eje_j's "filler" number contributes exactly 1 in edge-column jj. The target sum is built so that the vertex columns must sum to exactly kk and each edge column must sum to exactly 2 (using vertex contributions plus filler slack digits). A subset achieving the target sum corresponds exactly to a vertex cover of size kk. ```pseudocode // Reduction: 3-SAT --> CLIQUE function ThreeSATtoClique(phi): G = empty graph for each clause C_i in phi (i = 1..k): for each literal l in C_i: add node (i, l) to G // node tagged with clause index and literal for each pair of nodes (i, l1), (j, l2) with i != j: if l1 and l2 are not negations of each other: add edge between (i, l1) and (j, l2) return G, target_clique_size = k // Verifying direction: a clique of size k in G gives a satisfying assignment function DecodeClique(G, clique): assignment = {} for each node (i, l) in clique: var = variable_of(l) assignment[var] = true_if_positive_literal(l) return assignment // guaranteed consistent since clique has no conflicting literals ``` ```pseudocode // Reduction: VERTEX-COVER --> SUBSET-SUM (sketch) function VertexCoverToSubsetSum(G = (V, E), k): n = |V|, m = |E| base = 4 // base large enough to avoid digit carry-over for each vertex v_i in V: num[v_i] = base^i + sum( base^(n + j) for each edge e_j incident to v_i ) for each edge e_j in E: slackLow[e_j] = base^(n + j) // contributes 1 to that edge column slackHigh[e_j] = 2 base^(n + j) // contributes 2 to that edge column target = k (contribution to vertex columns, weight 1 each) + sum over edges of 2 * base^(n + j) // each edge column must total 2 S = { num[v] : v in V } union { slackLow[e], slackHigh[e] : e in E } return S, target ```

Figure
The reduction web: 3-SAT as the root, spreading to the classic NP-complete family
3-SAT (Cook–Levin root) Clique Independent Set Vertex Cover Hamiltonian Cycle TSP Subset -Sum Solid arrows: gadget reductions built explicitly in this article. Dashed: direct reduction (3-SAT → Subset-Sum) also possible.

Complexity & correctness

Membership in NP. Every problem discussed is in NP: a candidate solution (a satisfying assignment, a clique/cover/independent set, a Hamiltonian cycle, a tour, a subset) can be verified in polynomial time by direct inspection — checking clause satisfaction, edge membership, or an arithmetic sum, all linear or near-linear operations.

3-SAT ≤p\le_p Clique — correctness. The graph has O(3k)=O(k)O(3k) = O(k) nodes and O(k2)O(k^2) edges, built in O(k2)O(k^2) time. (⇒\Rightarrow) If φ\varphi is satisfiable, fix a satisfying assignment; in each clause at least one literal is true under it, so pick one such node per clause. Any two chosen nodes belong to different clauses and correspond to true literals under the same assignment, hence are consistent (never negations of each other), so an edge exists between them; this gives a clique of size kk. (⇐\Leftarrow) A clique of size kk must have exactly one node per clause group, since nodes inside one group are pairwise non-adjacent by construction. Because all pairwise chosen literals are mutually consistent (no two are negations), assigning each involved variable the truth value matching its chosen literal is a well-defined, non-contradictory partial assignment; extend arbitrarily to unmentioned variables. Every clause has its representative literal set true, so φ\varphi is satisfied.

Clique/Vertex-Cover/Independent-Set — correctness. These follow from the two set identities stated above, each verifiable directly from the definitions of clique, independent set, and covering all edges; no gadget is even needed, just a change of viewpoint on the same graph.

3-SAT ≤p\le_p Hamiltonian Cycle — correctness sketch. The variable gadgets are designed so that a Hamiltonian cycle is forced to traverse each variable's diamond chain in exactly one of two directions (this encodes a Boolean choice, and no other traversal completes a full cycle without revisiting a node). Clause nodes are attached with edges only to the literal-occurrences that would satisfy them; a clause node can be spliced into the cycle only if the corresponding variable gadget is traversed in the direction matching that literal. If φ\varphi is satisfiable, orient each variable gadget according to the satisfying assignment and splice in every clause node via a satisfied literal — a Hamiltonian cycle results. Conversely, any Hamiltonian cycle must splice in every clause node (since every node must be visited exactly once), and the splicing point for each clause forces a genuine satisfied literal, which decodes into a satisfying assignment. The construction size is polynomial: O(1)O(1) nodes per variable occurrence and O(1)O(1) edges per clause.

Hamiltonian Cycle ≤p\le_p TSP — correctness. Any Hamiltonian tour in KnK_n uses exactly nn edges. If all nn edges belong to GG (weight 1 each), the total is exactly n=Bn = B. If even one edge is an added edge (weight 2), the total exceeds nn, because the remaining n−1n-1 edges contribute at least n−1n - 1, giving a sum of at least n−1+2=n+1>Bn - 1 + 2 = n+1 > B. So a weight-≤B\le B tour exists iff a genuine Hamiltonian cycle in GG exists. Construction time is O(n2)O(n^2) to fill in the complete graph.

Vertex Cover ≤p\le_p Subset-Sum — correctness. The base is chosen large enough (≥\ge the maximum possible column sum, e.g., base == max degree +3+ 3) that no carrying occurs across digit columns during any candidate summation; this makes each digit column an independent constraint. The vertex columns force exactly kk vertices chosen; the edge columns, each needing total exactly 2, force at least one endpoint of every edge to be among the chosen vertices (the slack numbers fill in the remainder). Decoding a valid subset sum directly yields a size-kk vertex cover, and vice versa. The instance size is O((n+m)log⁡(base))O((n+m)\log(\text{base})) bits, polynomial in the original graph's size.

Complexity honesty. These are worst-case hardness results: they say no polynomial-time algorithm solves the general problem unless P = NP, not that every instance is hard in practice. Real inputs (sparse graphs, structured formulas, small treewidth) often admit fast exact or heuristic solutions. Also, note Subset-Sum is only weakly NP-complete — it has a pseudo-polynomial time algorithm (dynamic programming in O(nT)O(nT) time for target sum TT), unlike, say, 3-SAT or Clique, which are believed to have no such loophole. This distinction between weak and strong NP-completeness matters when approximation and exact algorithms are designed later.

Worked example

Trace the 3-SAT →\to Clique reduction on a tiny formula:

φ=(x1∨x2∨¬x3)∧(¬x1∨x2∨x3)∧(x1∨¬x2∨x3)\varphi = (x_1 \lor x_2 \lor \lnot x_3) \land (\lnot x_1 \lor x_2 \lor x_3) \land (x_1 \lor \lnot x_2 \lor x_3)

Three clauses, so k=3k = 3, and we seek a clique of size 3.

ClauseLiteral nodes created
C1C_1A1=x1A_1 = x_1, A2=x2A_2 = x_2, A3=¬x3A_3 = \lnot x_3
C2C_2B1=¬x1B_1 = \lnot x_1, B2=x2B_2 = x_2, B3=x3B_3 = x_3
C3C_3D1=x1D_1 = x_1, D2=¬x2D_2 = \lnot x_2, D3=x3D_3 = x_3

Edges connect nodes from different clauses whose literals are not negations of each other. For example A1(x1)A_1 (x_1) and B1(¬x1)B_1 (\lnot x_1) get no edge (direct contradiction); A1(x1)A_1 (x_1) and D1(x1)D_1 (x_1) get an edge (same literal, consistent); A2(x2)A_2 (x_2) and B3(x3)B_3(x_3) get an edge (unrelated variables, always consistent). Try the assignment x1=true,x2=true,x3=truex_1 = \text{true}, x_2 = \text{true}, x_3 = \text{true}. Check satisfaction: C1C_1: x1=Tx_1 = T ✓. C2C_2: x3=Tx_3 = T ✓. C3C_3: x1=Tx_1 = T ✓. So φ\varphi is satisfiable. Decode into a clique: pick A1(x1A_1 (x_1, true)) from C1C_1, B3(x3B_3 (x_3, true)) from C2C_2, D1(x1D_1 (x_1, true)) from C3C_3. Check all three pairs are mutually consistent (no negation pairs): A1A_1–B3B_3: x1x_1 vs x3x_3, different variables, edge exists. A1A_1–D1D_1: x1x_1 vs x1x_1, same literal, edge exists. B3B_3–D1D_1: x3x_3 vs x1x_1, different variables, edge exists. All three pairwise edges present ⇒{A1,B3,D1}\Rightarrow \{A_1, B_3, D_1\} is a clique of size 3, matching k=3k=3, confirming the correspondence. Now trace the failure direction with an inconsistent attempted clique: try {A1(x1),B1(¬x1),D1(x1)}\{A_1 (x_1), B_1(\lnot x_1), D_1(x_1)\}. Nodes A1A_1 and B1B_1 carry negated literals of x1x_1, so no edge connects them by construction — this triple is not a clique at all, illustrating why the graph correctly rejects assignments that would force x1x_1 to be both true and false.

Common pitfalls & traps

PitfallWhy it breaks the proof
Reducing in the wrong directionYou must reduce a known-hard problem into the new problem (L1≤pL2L_1 \le_p L_2), not the reverse; reducing the new problem into a known-easy one proves nothing about hardness.
Forgetting the "iff" (both directions)A reduction must be shown correct both ways: yes-instance maps to yes-instance, and no-instance maps to no-instance (equivalently, yes-target decodes to yes-source). Many flawed "proofs" only check one direction.
Non-polynomial gadget blow-upIf the gadget graph has exponentially many nodes (e.g., naive brute-force encodings of all assignments), the reduction is not efficient and proves nothing about NP-completeness.
Digit carry-over in Subset-Sum reductionsChoosing too small a base lets unrelated column sums interfere via carrying, silently breaking the "independent column constraint" argument.
Confusing search with decision versionsVertex Cover as a decision problem asks "is there a cover of size ≤k\le k?"; conflating this with "find the minimum cover" changes the complexity class framing (optimization vs. decision) even though they're polynomially equivalent.
Assuming weak inputs make the problem easy in generalA pseudo-polynomial algorithm for Subset-Sum (DP on the target value) doesn't contradict NP-completeness when numbers are exponentially large in the input's bit-length.

Pioneers & history

The theory of NP-completeness crystallized in the early 1970s, transforming an informal sense that "some problems just feel harder" into a rigorous mathematical framework with a precise completeness criterion.

Origins · 1 minStephen Cook and how this was discovered
SC
Stephen Cook
1939–present · University of Toronto, theoretical computer science

Cook's 1971 paper "The Complexity of Theorem-Proving Procedures" introduced the notion of polynomial-time reducibility and proved that Boolean satisfiability (SAT) is complete for NP — the seed result that all later NP-completeness proofs, including the reductions in this article, ultimately rest upon. He shared the 1982 Turing Award for this foundational work.

History
1971
Stephen Cook proves SAT is NP-complete (the Cook–Levin theorem, independently discovered by Leonid Levin in the Soviet Union).
1972
Richard Karp publishes "Reducibility Among Combinatorial Problems," proving 21 problems — including Clique, Vertex Cover, Hamiltonian Cycle, and (a variant close to) Subset-Sum — NP-complete via explicit polynomial-time reductions.
1979
Michael Garey and David Johnson publish Computers and Intractability, cataloguing hundreds of NP-complete problems and cementing the reduction methodology as standard practice.
1990
s–2000s: The theory of approximation algorithms and inapproximability (the PCP theorem) builds directly on this reduction web to show how hard it is even to approximate many of these problems.

Where this matters

Recognizing a real-world problem as an instance of Vertex Cover, Independent Set, or TSP is often the single most valuable step an engineer can take, because it immediately tells them what not to try. Network security teams model minimal monitoring-node placement (to observe every communication link) as Vertex Cover. Chip design and register allocation in compilers use graph-coloring-adjacent structures related to Independent Set to decide which variables can share hardware resources. Logistics and delivery-routing systems (ride-sharing dispatch, package delivery, circuit-board drilling) confront TSP directly, and industrial solvers (like Concorde) combine branch-and-bound with the same relaxations and cutting planes that stem from understanding TSP's NP-hardness. Bioinformatics uses Clique-finding to detect groups of mutually similar protein or gene-expression profiles, and Independent Set to resolve conflicting sequence alignments. Cryptographic hardness assumptions related to Subset-Sum (the knapsack problem) motivated early public-key cryptosystems, some later broken but historically important in the field's development. Constraint-solving engines (SAT solvers) built to attack 3-SAT directly, despite worst-case exponential behavior, now scale to industrial hardware-verification and software model-checking problems with millions of variables — a striking demonstration that worst-case NP-hardness and practical solvability are not the same story. This entire landscape connects forward to Coping with NP-Hardness and Approximation Algorithms and the Approximation Ratio, where knowing a problem is NP-complete becomes the starting point for practical engineering rather than a dead end.

Ask the tutor: Can you walk me through why the Hamiltonian Cycle variable gadget forces exactly two traversal directions and not more?

Why does proving one problem NP-complete let us conclude so much about totally unrelated-looking problems?

Because NP-completeness is defined relative to all of NP, not just to the source problem used in a reduction. Once SAT is shown NP-complete (Cook–Levin), every problem in NP already reduces to SAT by definition. If we then show SAT reduces to problem L2L_2 (say, Clique), transitivity of polynomial-time reductions means every problem in NP reduces to L2L_2 as well — through SAT as an intermediate step. So a single new gadget reduction instantly inherits the hardness of the entire class NP, not just of the one source problem used, which is why the "web" metaphor is apt: every node in the web is equally connected to all of NP.

Is Vertex Cover really "the same problem" as Independent Set, given the article says they interreduce so easily?

They are computationally equivalent for the decision question (does a set of the right size exist?), since SS independent iff V∖SV\setminus S is a cover translates one directly into the other with no gadget needed. But they are not identical in every practical sense: their optimization versions have different approximability behavior. Vertex Cover has a simple 2-approximation algorithm, while Independent Set is much harder to approximate (no constant-factor approximation exists under standard complexity assumptions). So decision-equivalence does not imply that all algorithmic properties transfer identically — a nuance explored further in the study of approximation ratios.

Why is the Hamiltonian Cycle reduction so much more intricate than the Clique reduction?

Clique's structure directly mirrors 3-SAT's clause structure: each clause naturally becomes a group of mutually exclusive choices, and consistency between literals directly becomes graph adjacency. Hamiltonian Cycle has no such natural "choice" primitive; a cycle is a global structural constraint (visit every node exactly once) rather than a local pairwise one. Encoding a Boolean variable's two possible truth values requires building a gadget subgraph whose only two possible traversal patterns correspond to "true" and "false," forcing the reduction to use dozens of auxiliary nodes per variable. This illustrates a general principle: reductions into "global" structural problems (cycles, colorings, connectivity) are usually harder to design than reductions into "local" ones (cliques, covers, satisfiability variants).

Does NP-completeness mean these problems are hopeless in practice?

No. NP-completeness is a worst-case statement: it guarantees no algorithm can solve all instances quickly (in polynomial time in the worst case) unless P = NP, but says nothing about typical, structured, or small instances. Modern SAT solvers routinely solve industrial instances with millions of variables using clever heuristics (clause learning, unit propagation, restarts) that exploit structure absent from adversarial worst-case instances. TSP solvers using branch-and-cut solve instances with tens of thousands of cities to provable optimality. NP-completeness tells you to stop searching for a guaranteed fast algorithm and instead invest in heuristics, approximation, or exploiting special structure — a mindset shift, not a dead end.

Why does the Subset-Sum reduction need such a carefully chosen numeric base?

The reduction encodes multiple independent constraints (one per vertex-selection count, one per edge-coverage requirement) as separate digit columns of a single large number. If the base is too small, a sum of several numbers in one column can "carry" into the next column, corrupting the neighboring constraint's arithmetic — effectively mixing unrelated parts of the encoding together. Choosing the base larger than the maximum possible column sum (accounting for the number of terms that could contribute to any one column, such as vertex degree) guarantees no carrying can occur for any subset, so each digit column behaves as an independent, uncorrupted linear constraint, exactly as the correctness proof requires.

Are 3-SAT, Clique, Vertex Cover, Hamiltonian Cycle, TSP, and Subset-Sum "equally hard" in some finer sense?

They are equivalent under polynomial-time reductions (all NP-complete), but this equivalence is coarse — it ignores constant factors, exact exponential growth rates, and approximability. Some (Clique, Independent Set) are proven hard to approximate at all under standard assumptions; others (Vertex Cover, TSP with triangle inequality) admit good constant-factor approximations. Subset-Sum is only weakly NP-complete and has a pseudo-polynomial algorithm, while the others are strongly NP-complete with no such loophole believed to exist. So while they're identical from the coarse lens of "polynomial vs. not," they diverge sharply once approximation and practical algorithm design enter the picture.

Before this

Where this leads