A graph is bipartite iff it has no odd cycle iff it is 2-colourable. Test with BFS/DFS colouring per component, or online with a parity DSU. Bipartiteness unlocks the matching toolbox: König (min vertex cover = max matching), max independent set matching, Hall’s condition, Dilworth for posets (Bipartite Matching).

// returns colours (0/1), or an odd cycle if the graph isn't bipartite
pair<vector<int>, vector<int>> twoColour(const vector<vector<int>>& g) {
    int n = sz(g); vector<int> c(n, -1), par(n, -1), dep(n);
    for (int s = 0; s < n; s++) {
        if (c[s] >= 0) continue;
        c[s] = 0; queue<int> q; q.push(s);
        while (sz(q)) {
            int u = q.front(); q.pop();
            for (int v : g[u]) {
                if (c[v] < 0) { c[v] = c[u] ^ 1, par[v] = u, dep[v] = dep[u] + 1, q.push(v); continue; }
                if (c[v] != c[u]) continue;
                vector<int> a{u}, b{v};                           // climb to the common ancestor
                while (a.back() != b.back()) {
                    if (dep[a.back()] >= dep[b.back()]) a.push_back(par[a.back()]); else b.push_back(par[b.back()]);
                }
                b.pop_back(); a.insert(a.end(), b.rbegin(), b.rend());
                return {{}, a};                                   // odd cycle u ... lca ... v (edge v-u closes it)
            }
        }
    }
    return {c, {}};
}

Online and offline variants

  • Parity DSU: each vertex stores its parity relative to its root; uniting requires opposite parities; an edge inside a component with equal parities creates an odd cycle. Supports “is the graph still bipartite after each added edge” in near-constant time (DSU).
  • With deletions (offline): segment tree over time with a rollback parity DSU, (CF 813F).
  • Edges in a range of indices (“is the subgraph of edges bipartite?”): two pointers on the largest bipartite window with rollback or a link-cut tree maintaining a maximum spanning forest by deletion time; or the divide-and-conquer “minimal for each ” monotonicity (JOI “Joker”).

The parity / double-cover trick

To ask about walks of a given parity (“is there a walk of odd length from to ”, “shortest odd walk”, “reach in exactly steps for huge ”), BFS on the bipartite double cover: vertices , edges . In a connected non-bipartite graph, every vertex is reachable with both parities; walks of length exactly exist iff the shortest walk of the right parity has length (pad with back-and-forth steps).

Where bipartite structure hides

  • grids (chessboard colouring): no two adjacent cells chosen = independent set; domino placement = matching;
  • rows vs columns: placing rooks, “one marked cell per row and column”;
  • trees and forests (depth parity);
  • even/odd sums: “no two chosen numbers sum to a prime” splits by parity (primes are odd);
  • left/right parts of a DAG path cover;
  • positions vs values of a permutation.

Facts about bipartite graphs

FactStatement
Königmax matching = min vertex cover
Gallaimax independent set + min vertex cover (any graph)
König (edges)min edge cover = − max matching (no isolated vertices)
Halla matching saturating exists iff for all
regular bipartiteevery -regular bipartite graph () has a perfect matching; its edges split into perfect matchings
edge colouringbipartite graphs are -edge-colourable (König’s line colouring theorem) (Colouring)
countingperfect matchings = permanent of the biadjacency matrix: p-hard in general, by Ryser

Proofs of the matching theorems are in Bipartite Matching.

Bipartiteness is exactly the boundary between easy and hard for several of these: -colouring for is NP-complete (even restricted to planar graphs, even for , Colouring), and general-graph matching/vertex-cover/independent-set lose their polynomial algorithms or become NP-hard outright (vertex cover and independent set; matching stays polynomial via Blossom, just slower):

QuantityBipartiteGeneral
maximum matching (Hopcroft–Karp) (Blossom)
minimum vertex cover max matching (König)NP-hard
maximum independent set max matchingNP-hard
min-cost perfect matching (Hungarian) (weighted Blossom)

Odd cycle transversal: the minimum number of vertices to delete to make a graph bipartite. NP-hard in general, but fixed-parameter tractable in the number of vertices deleted.