Maximum Bipartite Matching

Prerequisites: Bipartite Graphs, Graph Matching

Introduction

This article studies the maximum matching problem in a bipartite graph G=(X,Y,E)G=(X,Y,E).

A familiar example of bipartite matching is pairing men and women. Suppose there are several men (XX) and women (YY); each person may be paired at most once, and the allowed pairings are specified by a list (EE). The task of maximum bipartite matching is to find as many pairs as possible under these restrictions.

Note

We assume that a partition (or coloring) of the bipartite graph's vertex set VV is known: V=X∪YV=X\cup Y. If the partition of VV is not known in advance, it can be found using the bipartite-graph coloring algorithm in O(∣V∣+∣E∣)O(|V|+|E|) time.

Kuhn Algorithm

The Kuhn algorithm is a direct application of Berge's lemma. It is also part of the Hungarian algorithm.

Process

To find a maximum matching, the algorithm enumerates the vertices one by one, finds an augmenting path starting from each vertex, and augments along it. An augmenting path always has odd length, so in a bipartite graph its endpoints must lie in different parts. Therefore, it suffices to consider augmenting paths starting from the left part.

To find an augmenting path, orient the bipartite graph according to the current matching MM. Along an augmenting path (or any alternating path) starting from an unmatched left vertex, non-matching edges go from the left part to the right part, while matching edges go from the right part to the left part. Thus, orient every non-matching edge toward the right part and every matching edge toward the left part. Finding an augmenting path becomes finding a simple directed path from an unmatched left vertex to an unmatched vertex, which can be done with DFS or BFS in O(∣E∣)O(|E|) time.

Figure: bigraph match 1

(In the figure, dark vertices are matched, light vertices are unmatched, red edges are matching edges, black edges are non-matching edges, and arrows show the orientation induced by the current matching. The path 1→8→3→11→6→121\rightarrow 8\rightarrow 3\rightarrow 11\rightarrow 6\rightarrow 12 is an augmenting path relative to the current matching.)

Initially, all edges point toward the right part. Whenever an augmenting path is found, reverse every edge on the path to reflect the reversal of its matching status. At the end, exactly the edges pointing toward the left part are matching edges.

Since at most O(∣V∣)O(|V|) left vertices need to be enumerated once each, the total time complexity is O(∣V∣∣E∣)O(|V||E|).

Optimizations

Some simple techniques can improve the constants of the Kuhn algorithm:

  1. Kuhn's algorithm is based on Berge's lemma, which does not require the two parts of a bipartite graph to be specified in advance. Thus, Kuhn's algorithm remains correct even when the two parts are not explicitly identified, as long as the graph is bipartite. In practice, however, coloring the graph first and determining its left and right parts is often more efficient.
  2. The time complexity of the Kuhn algorithm described above is actually O(∣X∣∣E∣)O(|X||E|), so the smaller of the two parts can be chosen as the left part XX.
  3. When searching for augmenting paths, the visited marks used to avoid repeated searches do not need to be cleared before every DFS. Before clearing them, try to find augmenting paths from all unmatched left vertices. In one such round every edge is visited at most once, so the complexity remains O(∣E∣)O(|E|); however, several augmenting paths may be found in one round. Therefore, the total number of rounds kk is at most ∣M∣+1|M|+1, where MM is a maximum matching, and the overall complexity becomes O(k∣E∣)O(k|E|).
  4. When searching for an augmenting path, consider unmatched right vertices first, since this gives a shorter augmenting path.
  5. Berge's lemma does not require the initial matching to be empty. Kuhn's algorithm can therefore begin with a random set of pairwise disjoint edges as an initial matching, reducing later searches. If optimization 3 is used, this optimization can be omitted.

The worst-case complexity is still O(∣V∣∣E∣)O(|V||E|), but a fully optimized Kuhn algorithm performs well in practice. To prevent particular inputs from forcing the worst case, randomly shuffle the order of edges or vertices before matching.

Reference Implementation

The implementation does not need to maintain the orientations explicitly; it only needs to maintain the vertex matched with each vertex.

Template Problem: Library Checker - Matching on Bipartite Graph
#include <algorithm>
#include <ctime>
#include <iostream>
#include <random>
#include <tuple>
#include <vector>

std::mt19937_64 rng(
    static_cast<std::mt19937_64::result_type>(std::time(nullptr)));

struct BipartiteGraph {
  int n1, n2;                       // number of vertices in X and Y, resp.
  std::vector<std::vector<int>> g;  // edges from X to Y
  std::vector<int> ma, mb;  // matches from X to Y and from Y to X, resp.
  std::vector<bool> vis;    // visiting marks for DFS.

  BipartiteGraph(int n1, int n2)
      : n1(n1), n2(n2), g(n1), ma(n1, -1), mb(n2, -1) {}

  // Add an edge from u in X to v in Y.
  void add_edge(int u, int v) { g[u].emplace_back(v); }

  // Find an augmenting path starting at u.
  bool dfs(int u) {
    vis[u] = true;
    // Heuristic: find unsaturated vertices whenever possible.
    for (int v : g[u]) {
      if (mb[v] == -1) {
        ma[u] = v;
        mb[v] = u;
        return true;
      }
    }
    for (int v : g[u]) {
      if (!vis[mb[v]] && dfs(mb[v])) {
        ma[u] = v;
        mb[v] = u;
        return true;
      }
    }
    return false;
  }

  // Kuhn's maximum matching algorithm.
  std::vector<std::pair<int, int>> kuhn_maximum_matching() {
    // Randomly shuffle the edges.
    for (int u = 0; u < n1; ++u) {
      std::shuffle(g[u].begin(), g[u].end(), rng);
    }
    // Find a maximal set of vertex-disjoint augmenting paths in each round.
    while (true) {
      bool succ = false;
      vis.assign(n1, false);
      for (int u = 0; u < n1; ++u) {
        succ |= ma[u] == -1 && dfs(u);
      }
      if (!succ) break;
    }
    // Collect the matched pairs.
    std::vector<std::pair<int, int>> matches;
    matches.reserve(n1);
    for (int u = 0; u < n1; ++u) {
      if (ma[u] != -1) {
        matches.emplace_back(u, ma[u]);
      }
    }
    return matches;
  }
};

int main() {
  std::ios::sync_with_stdio(false), std::cin.tie(nullptr);
  int n1, n2, m;
  std::cin >> n1 >> n2 >> m;
  BipartiteGraph gr(n1, n2);
  for (int i = 0; i < m; ++i) {
    int u, v;
    std::cin >> u >> v;
    gr.add_edge(u, v);
  }
  auto res = gr.kuhn_maximum_matching();
  std::cout << res.size() << '\n';
  for (int i = 0; i < res.size(); ++i) {
    std::cout << res[i].first << ' ' << res[i].second << '\n';
  }
  return 0;
}

Hopcroft–Karp Algorithm

The Hopcroft–Karp algorithm further optimizes the Kuhn algorithm's search for augmenting paths, reducing the total number of rounds to O(∣V∣1/2)O(|V|^{1/2}) and achieving time complexity O(∣V∣1/2∣E∣)O(|V|^{1/2}|E|). It is in fact a special case of Dinic's algorithm.

Process

The algorithm still searches for augmenting paths, but to complete the matching in fewer rounds, it uses the following strategy in each round:

  1. Orient matching edges toward the left part and non-matching edges toward the right part.
  2. Starting from every unmatched left vertex, run BFS on the directed graph and record the level d(v)d(v) of each visited vertex, stopping when an unmatched right vertex first appears. If BFS finishes without finding an unmatched right vertex, the current matching is maximum.
  3. Starting from each unmatched left vertex in turn, run DFS to find and augment along an augmenting path. During DFS, follow edges whose levels are consecutive and strictly increasing (that is, d(v′)=d(v)+1d(v') = d(v) + 1), and visit only vertices not yet visited during the current DFS round. In particular, DFS does not visit vertices that BFS in the previous step did not reach.

In network-flow terminology, step 2 constructs a level graph, while step 3 finds a blocking flow in the level graph. A level graph is one in which every edge goes from one level to the next; in this context, a blocking flow is a maximal collection of pairwise vertex-disjoint augmenting paths. The collection found in step 3 is necessarily maximal: otherwise, if a new augmenting path existed, the algorithm would already have found it when it enumerated its starting point.

Compared with the Kuhn algorithm above, the key change in Hopcroft–Karp is adding the construction of a level graph before finding a blocking flow. DFS on the level graph restricts the algorithm to shortest paths to each vertex. The benefit is that the lengths of the augmenting paths found in successive rounds are strictly increasing. Moreover, one can prove that, before a maximum matching is found, the length of an augmenting path increases at most 3∣M∣1/23|M|^{1/2} times, where ∣M∣|M| is the size of a maximum matching. Thus the total number of augmentation rounds is bounded by O(∣M∣1/2)O(|M|^{1/2}), giving time complexity O(∣M∣1/2∣E∣)O(|M|^{1/2}|E|). Since 2∣M∣≤∣V∣2|M|\le |V|, the time complexity can also be written as the looser upper bound O(∣V∣1/2∣E∣)O(|V|^{1/2}|E|).

Proof

First, we show that the lengths of the augmenting paths found in successive rounds are strictly increasing.

Suppose the BFS in the current round reaches level ℓ\ell. Since all unmatched right vertices found by BFS are on the same level, every augmenting path found by DFS in this round has length ℓ\ell. We need to prove that after augmenting along the set of paths {Pi}\{P_i\} found in this round, the reoriented directed graph contains no augmenting path of length at most ℓ\ell.

In fact, if PP is a shortest augmenting path relative to MM and P′P' is an augmenting path relative to M⊕PM\oplus P, then ∣P′∣≥∣P∣+2∣P∩P′∣|P'|\ge |P| + 2|P\cap P'|. This is because N=(M⊕P)⊕P′N=(M\oplus P)\oplus P' augments relative to MM twice. Thus, by an argument analogous to the proof of Berge's lemma, the symmetric difference M⊕N=P⊕P′M\oplus N=P\oplus P' contains at least two vertex-disjoint augmenting paths relative to MM, namely P1P_1 and P2P_2. By the minimality of PP,

2∣P∣≤∣P1∣+∣P2∣≤∣P⊕P′∣=∣P∣+∣P′∣−2∣P∩P′∣.2|P|\le |P_1|+|P_2|\le |P\oplus P'| = |P| + |P'| - 2|P\cap P'|.

This shows that ∣P′∣≥∣P∣+2∣P∩P′∣|P'|\ge |P| + 2|P\cap P'|. Therefore, if after augmenting along {Pi}\{P_i\} a new augmenting path P′P' still had the same length, it would have to be disjoint from every one of them, contradicting the maximality of {Pi}\{P_i\}. This contradiction shows that after augmenting along the blocking flow, every new augmenting path is strictly longer.

Finally, we show that the length of an augmenting path increases at most 3∣M∣1/23|M|^{1/2} times.

Let p=⌊∣M∣1/2⌋p=\lfloor|M|^{1/2}\rfloor. After the first pp rounds, the remaining augmenting paths have length at least ∣M∣1/2|M|^{1/2}. Let the current matching be MpM_p. As in the preceding case, we can show that the graph (V,M⊕Mp)(V,M\oplus M_p) contains ∣M∣−∣Mp∣|M|-|M_p| pairwise vertex-disjoint augmenting paths relative to MpM_p. Each augmenting path uses at least ∣M∣1/2/2|M|^{1/2}/2 matching edges from MM, so the total number of these paths is at most 2∣M∣1/22|M|^{1/2}; that is, ∣M∣−∣Mp∣≤2∣M∣1/2|M|-|M_p|\le 2|M|^{1/2}. Thus, starting from MpM_p, at most 2∣M∣1/22|M|^{1/2} more augmentations are possible, which also means that the algorithm performs at most 2∣M∣1/22|M|^{1/2} more augmentation rounds. Hence, the total increase in augmenting-path length is at most 3∣M∣1/23|M|^{1/2}.

This is only a worst-case estimate for the Hopcroft–Karp algorithm. In a random graph, the time complexity of Hopcroft–Karp is in fact O(∣E∣log⁡∣V∣)O(|E|\log |V|) with high probability.1

Optimization

When building the level graph, Hopcroft–Karp, like the usual Dinic algorithm, stops upon reaching an unmatched right vertex. For bipartite matching alone, however, this is unnecessary. Moreover, premature termination of BFS restricts the scope of subsequent DFS and limits the number of augmenting paths found in each round, slowing the overall matching process. On some graphs, it is even less efficient than the optimized Kuhn algorithm. A simple improvement is therefore to let BFS continue instead of terminating early, and build the level graph for every reachable vertex.

Correctness Proof

In the optimized algorithm, the augmenting paths in a blocking flow no longer all have the same length, so the preceding complexity proof no longer applies directly. However, by constructing an auxiliary graph for each round, we can still show that the shortest augmenting-path length strictly increases, preserving the worst-case complexity bound.

Let the bipartite graph be G=(X,Y,E)G=(X,Y,E) with current matching MM. Let W⊆YW\subseteq Y be the set of unmatched right vertices reachable by BFS, and let the shortest augmenting path reaching y∈Wy\in W have length d(y)d(y). Set dmax=max⁡y∈Wd(y)d_\text{max} = \max_{y\in W}d(y). For each y∈Wy\in W, create a chain starting at yy of length dmax−d(y)d_\text{max} - d(y), marking its new vertices alternately as left and right vertices and its new edges alternately as matching and non-matching edges. Let the resulting graph be G′=(X′,Y′,E′)G'=(X',Y',E'), with matching M′M' and shortest augmenting-path length dmaxd_\text{max}. The augmenting paths found in the level graph of GG relative to MM—that is, the shortest augmenting paths reaching the corresponding vertices—are in bijection with the globally shortest augmenting paths in G′G' relative to M′M'. Therefore, finding a blocking flow and augmenting in the level graph of GG is equivalent to doing so in the level graph of G′G'. By the preceding proof, after augmentation, G′G' has no augmenting path of length dmaxd_\text{max}. Hence, GG has no augmenting path of length dmin=min⁡y∈Wd(y)d_\text{min}=\min_{y\in W} d(y) either: such a path would extend along the newly added alternating chain and necessarily correspond to an augmenting path in G′G' of length dmaxd_\text{max}. Thus, the shortest augmenting-path length is again strictly increasing from one round to the next, and the overall complexity remains O(∣M∣1/2∣E∣)O(|M|^{1/2}|E|).

Reference Implementation

Template Problem: Library Checker - Matching on Bipartite Graph
#include <algorithm>
#include <iostream>
#include <queue>
#include <tuple>
#include <vector>

struct BipartiteGraph {
  int n1, n2;                       // number of vertices in X and Y, resp.
  std::vector<std::vector<int>> g;  // edges from X to Y
  std::vector<int> ma, mb;  // matches from X to Y and from Y to X, resp.
  std::vector<int> dist;    // distance from unsaturated vertices in X.

  BipartiteGraph(int n1, int n2)
      : n1(n1), n2(n2), g(n1), ma(n1, -1), mb(n2, -1) {}

  // Add an edge from u in X to v in Y.
  void add_edge(int u, int v) { g[u].emplace_back(v); }

  // Build the level graph.
  bool bfs() {
    dist.assign(n1, -1);
    std::queue<int> q;
    for (int u = 0; u < n1; ++u) {
      if (ma[u] == -1) {
        dist[u] = 0;
        q.emplace(u);
      }
    }
    // Build the level graph for all reachable vertices.
    bool succ = false;
    while (!q.empty()) {
      int u = q.front();
      q.pop();
      for (int v : g[u]) {
        if (mb[v] == -1) {
          succ = true;
        } else if (dist[mb[v]] == -1) {
          dist[mb[v]] = dist[u] + 1;
          q.emplace(mb[v]);
        }
      }
    }
    return succ;
  }

  // Find an augmenting path starting at u.
  bool dfs(int u) {
    for (int v : g[u]) {
      if (mb[v] == -1 || (dist[mb[v]] == dist[u] + 1 && dfs(mb[v]))) {
        ma[u] = v;
        mb[v] = u;
        return true;
      }
    }
    dist[u] = -1;  // Mark this point as inreachable after one visit.
    return false;
  }

  // Hopcroft-Karp maximum matching algorithm.
  std::vector<std::pair<int, int>> hopcroft_karp_maximum_matching() {
    // Build the level graph and then find a blocking flow.
    while (bfs()) {
      for (int u = 0; u < n1; ++u) {
        if (ma[u] == -1) {
          dfs(u);
        }
      }
    }
    // Collect the matched pairs.
    std::vector<std::pair<int, int>> matches;
    matches.reserve(n1);
    for (int u = 0; u < n1; ++u) {
      if (ma[u] != -1) {
        matches.emplace_back(u, ma[u]);
      }
    }
    return matches;
  }
};

int main() {
  std::ios::sync_with_stdio(false), std::cin.tie(nullptr);
  int n1, n2, m;
  std::cin >> n1 >> n2 >> m;
  BipartiteGraph gr(n1, n2);
  for (int i = 0; i < m; ++i) {
    int u, v;
    std::cin >> u >> v;
    gr.add_edge(u, v);
  }
  auto res = gr.hopcroft_karp_maximum_matching();
  std::cout << res.size() << '\n';
  for (int i = 0; i < res.size(); ++i) {
    std::cout << res[i].first << ' ' << res[i].second << '\n';
  }
  return 0;
}

Reduction to the Maximum-Flow Problem

The maximum bipartite matching problem can be reduced to the maximum-flow problem.

Figure: bigraph match 2

As shown in the figure, add two vertices as the source and sink. From the source, connect an edge to every left vertex; from every right vertex, add an edge to the sink; and for every undirected edge in the bipartite graph, add an edge directed from the left vertex to the right vertex. Every edge has capacity 11. Each flow in the resulting directed graph corresponds bijectively to a matching in the bipartite graph, and the value of the flow is the size of the corresponding matching. Therefore, solving maximum bipartite matching is equivalent to solving the maximum flow in the corresponding directed graph.

Any algorithm that solves maximum flow can be used to solve maximum bipartite matching. It is easy to see that the Kuhn and Hopcroft–Karp algorithms are special cases of corresponding maximum-flow algorithms. Likewise, algorithms such as the push–relabel algorithm can also solve maximum bipartite matching. However, note that any maximum-flow algorithm needs to be optimized specifically when applied to bipartite matching to avoid excessive constant factors.

Linear Programming Form

Like other maximum-flow problems, maximum matching in a bipartite graph G=(V,E)G=(V,E) can be formulated as a linear program. If xe∈{0,1}x_e\in\{0,1\} indicates whether edge ee belongs to the matching, we obtain the following linear program:

max⁡{xe}  ∑e∈Exesubject to ∑e∼vxe≤1, ∀v∈V,xe≥0, ∀e∈E.\begin{aligned} \max_{\{x_e\}}\;& \sum_{e\in E}x_e \\ \text{subject to } & \sum_{e\sim v} x_{e} \le 1,~\forall v\in V,\\ & x_e\ge 0,~\forall e\in E. \end{aligned}

Here, e∼ve\sim v denotes incidence, meaning that vertex vv is an endpoint of edge ee. In addition to nonnegativity constraints, the problem requires each vertex v∈Vv\in V to be incident to at most one edge, which is exactly the definition of a matching. Thus, every matching corresponds to an integer point in the feasible region of this linear program.

The converse is not true. In a feasible solution, xex_e may be fractional, which does not represent an actual matching. Nevertheless, for a bipartite graph GG, every extreme-point solution of the linear program above is integral. This means that the optimum of the objective function is always attained at an integer point, so noninteger cases need not be considered. This property does not hold for general graphs, so the linear program above is not equivalent to the maximum matching problem on general graphs.

The dual of this linear program can be written as follows:

min⁡{yv}  ∑v∈Vyvsubject to yu+yv≥1, ∀(u,v)∈E,yv≥0, ∀v∈V.\begin{aligned} \min_{\{y_v\}}\;& \sum_{v\in V}y_v \\ \text{subject to } & y_u+y_v \ge 1,~\forall (u,v)\in E,\\ & y_v\ge 0,~\forall v\in V. \end{aligned}

We will soon see that this is exactly the minimum vertex-cover problem for bipartite graphs.

Dulmage–Mendelsohn Decomposition

Using a maximum matching in a bipartite graph, we can partition the vertices into several disjoint subsets, fully characterizing the distribution and structural properties of all maximum matchings in the graph. This is the Dulmage–Mendelsohn decomposition. In algorithm competitions, this decomposition can identify critical vertices and critical edges in a maximum matching, and can then be used to determine whether the maximum matching is unique or to solve problems such as bipartite graph games.

Construction

For the bipartite graph G=(X,Y,E)G=(X,Y,E), let MM be a maximum matching.

Figure: bigraph match 4

As shown in the figure, define the following three subsets of all vertices V=X∪YV=X\cup Y:

  • Even-reachable vertices E\mathcal E: the set of vertices reachable from an unmatched vertex by an alternating path of even length;
  • Odd-reachable vertices O\mathcal O: the set of vertices reachable from an unmatched vertex by an alternating path of odd length;
  • Unreachable vertices U\mathcal U: the set of vertices that cannot be reached from an unmatched vertex by an alternating path.

The three vertex sets E,O,U\mathcal E,\mathcal O,\mathcal U obtained this way have the following properties:

Properties
  1. The sets E,O,U\mathcal E,\mathcal O,\mathcal U form a partition of the vertex set, and this partition is independent of the choice of maximum matching MM.
  2. Every maximum matching of GG contains a perfect matching among the vertices of U\mathcal U, and matches every vertex in O\mathcal O to a vertex in E\mathcal E. In other words, the size of a maximum matching of GG is ∣O∣+∣U∣/2|\mathcal O|+|\mathcal U|/2.
  3. The graph GG contains no edge connecting a vertex in E\mathcal E to a vertex in E∪U\mathcal E\cup\mathcal U.
Proof

By definition, U\mathcal U is disjoint from E∪O\mathcal E\cup\mathcal O. It remains to prove that E\mathcal E and O\mathcal O are disjoint. Otherwise, for a vertex v∈E∩Ov\in\mathcal E\cap\mathcal O, there is an alternating path of even length from an unmatched vertex aa to vv, and an alternating path of odd length from an unmatched vertex bb to vv. Since GG is bipartite, a≠ba\neq b, and the edges by which the two paths reach vv are respectively a matching edge and a non-matching edge. Connecting the two paths therefore gives an alternating path from aa through vv to bb. This is an augmenting path, contradicting the fact that MM is a maximum matching. Hence E∩O=∅\mathcal E\cap\mathcal O=\varnothing.

  1. Let M′M' be a maximum matching different from MM. Repeating the proof of Berge's lemma shows that M′⊕MM'\oplus M consists only of even-length paths and even cycles. Starting from maximum matching MM, we can flip the edges in these connected components (swapping matching and non-matching edges) one component at a time to obtain maximum matching M′M'. When an even cycle is flipped, unmatched vertices remain unmatched, and the parity of the lengths of alternating paths starting from them does not change; when an even-length path is flipped, the matching status of its two endpoints is exchanged, but the parity of the path length from either endpoint to any vertex on the path is the same. Therefore, throughout the flipping process, the sets E,O,U\mathcal E,\mathcal O,\mathcal U remain unchanged. This shows that the decomposition is independent of the choice of maximum matching MM.
  2. If a matching edge occurs on an alternating path starting from an unmatched vertex vv, its two endpoints necessarily have different parity of distance from vv and therefore belong to E\mathcal E and O\mathcal O, respectively; otherwise, both endpoints belong to U\mathcal U. Thus, every matching edge in a maximum matching is either an EO\mathcal E\mathcal O edge or a UU\mathcal U\mathcal U edge. Conversely, an unmatched vertex can be reached by the length-zero alternating path starting from itself, so unmatched vertices occur only in E\mathcal E; hence every vertex in O\mathcal O and U\mathcal U is matched. Simple counting shows that the size of a maximum matching is ∣O∣+∣U∣/2|\mathcal O|+|\mathcal U|/2.
  3. By definition, any vertex in E\mathcal E, including aa, can be reached from an unmatched vertex vv by an alternating path of even length; that is, a vertex in E\mathcal E is either unmatched or the alternating path PP reaching it ends with a matching edge. If the graph GG contains an edge connecting aa to a vertex in E∪U\mathcal E\cup\mathcal U, namely bb, then by the preceding paragraph this edge is necessarily non-matching, and we can extend the alternating path PP along it. This puts bb in O\mathcal O, contradicting the first property. Therefore, the graph GG contains no edge connecting a vertex in E\mathcal E to a vertex in E∪U\mathcal E\cup\mathcal U.

The decomposition V=E∪O∪UV=\mathcal E\cup\mathcal O\cup\mathcal U of the vertex set obtained this way is called the Dulmage–Mendelsohn decomposition. After finding a maximum matching with the algorithms described above, the decomposition can be computed by BFS in O(∣V∣+∣E∣)O(|V|+|E|) time.

Critical Vertices of a Maximum Matching

If a vertex vv is matched in every maximum matching of the bipartite graph GG, it is called a critical vertex of the maximum matching. The following result says that a vertex is critical if and only if, in one maximum matching, there is no even-length alternating path from an unmatched vertex to that vertex.

Theorem

Let the Dulmage–Mendelsohn decomposition of the bipartite graph G=(X,Y,E)G=(X,Y,E) be V=E∪O∪UV=\mathcal E\cup\mathcal O\cup\mathcal U. Then a vertex v∈Vv\in V is critical if and only if v∈O∪Uv\in\mathcal O\cup \mathcal U.

Proof

By the properties of the Dulmage–Mendelsohn decomposition, in graph GG, the vertices in O\mathcal O and U\mathcal U are matched in every maximum matching. Therefore, every vertex in O∪U\mathcal O\cup \mathcal U is critical. It remains to show that no vertex in E\mathcal E is critical. If, in a maximum matching MM, a vertex a∈Ea\in\mathcal E is critical, there is an even-length alternating path PP connecting aa to an unmatched vertex b∈Eb\in\mathcal E. Flipping all edges on this path gives a maximum matching M⊕PM\oplus P in which aa is unmatched. Therefore, no vertex in E\mathcal E is critical.

Thus, to find the critical vertices of a maximum matching, it suffices to compute the Dulmage–Mendelsohn decomposition.

Critical Edges of a Maximum Matching

Similarly, if an edge ee is a matching edge in every maximum matching of the bipartite graph GG, it is called a critical edge of the maximum matching. The maximum matching is unique if and only if every matching edge in one of its maximum matchings is critical.

Theorem

Let the Dulmage–Mendelsohn decomposition of the bipartite graph G=(X,Y,E)G=(X,Y,E) be V=E∪O∪UV=\mathcal E\cup\mathcal O\cup\mathcal U, and let MM be one of its maximum matchings. Then an edge e∈Ee\in E is critical if and only if both endpoints of ee are in U\mathcal U, ee is a matching edge in MM, and relative to MM there is no alternating cycle containing ee.

Proof

The endpoints of a critical edge must be critical vertices. By the properties of the Dulmage–Mendelsohn decomposition, matching edges can only be EO\mathcal E\mathcal O edges or UU\mathcal U\mathcal U edges. However, no vertex in E\mathcal E is critical, so a critical edge must be an UU\mathcal U\mathcal U edge. Of course, a critical edge must also be a matching edge in MM. Let e∈Me\in M be an UU\mathcal U\mathcal U edge. It is not critical if and only if there is another maximum matching M′≠MM'\neq M such that e∈M⊕M′e\in M\oplus M'. Repeating the proof of Berge's lemma shows that M′⊕MM'\oplus M consists only of even-length paths and even cycles. One endpoint of each such path is unmatched relative to MM, so no vertex on a path can be in U\mathcal U, contradicting the choice of ee. Hence, ee can occur only on an even cycle. Therefore, an UU\mathcal U\mathcal U edge e∈Me\in M is not critical if and only if, relative to MM, there is an alternating cycle containing ee. This proves the claim.

Thus, to find the critical edges of a maximum matching, perform the following steps:

  1. Find graph GG's maximum matching MM;
  2. Orient according to MM the edges of graph GG, obtaining directed graph GMG_M;
  3. Use BFS to find the set U\mathcal U in the Dulmage–Mendelsohn decomposition, that is, the set of vertices unreachable from unmatched vertices along alternating paths;
  4. Use Tarjan's algorithm to find all strongly connected components of directed graph GMG_M;
  5. Traverse the edges in matching MM. If both endpoints are in U\mathcal U but are not in the same strongly connected component, it is a critical edge.

After a maximum matching has been obtained, the remaining steps take O(∣V∣+∣E∣)O(|V|+|E|) time.

The maximum bipartite matching algorithm can be used to solve other combinatorial optimization problems.

Minimum Vertex Cover in a Bipartite Graph

The minimum vertex cover problem asks us to choose as few vertices as possible in an undirected graph so that every edge has at least one selected endpoint.

The minimum vertex cover problem is NP-hard for general graphs, but for bipartite graphs, König's theorem reduces it to maximum matching, so it can be solved efficiently. The proof of the theorem also gives a construction of a minimum vertex cover.

König's Theorem

In a bipartite graph, the number of vertices in a minimum vertex cover equals the number of edges in a maximum matching.

Proof

Let the bipartite graph G=(X,Y,E)G=(X,Y,E) have maximum matching MM. Let GG's unmatched left vertices be UU, and let ZZ be the set of vertices reachable from them along alternating paths. Then C=(X∖Z)∪(Y∩Z)C=(X\setminus Z)\cup(Y\cap Z) is the desired minimum vertex cover.

Figure: bigraph match 3

First, CC is a vertex cover. Suppose otherwise: there is an edge (u,v)∈E(u,v)\in E with u∈X∩Zu\in X\cap Z and v∈Y∖Zv\in Y\setminus Z. Let PuP_u be an alternating path reaching uu. If (u,v)(u,v) is a matching edge, the last edge of PuP_u is (v,u)(v,u), contradicting v∉Zv\notin Z; if (u,v)(u,v) is not a matching edge, we can extend along edge (u,v)(u,v) the path PuP_u to obtain an alternating path reaching vv, again contradicting v∉Zv\notin Z. These contradictions show that every edge has at least one endpoint in CC, so CC is a vertex cover.

It remains to show that CC is a minimum vertex cover. To cover all edges of the maximum matching MM, any vertex cover needs at least ∣M∣|M| vertices. Therefore, it suffices to prove ∣C∣=∣M∣|C|=|M|, which makes it a minimum vertex cover. This is equivalent to proving that, besides containing one endpoint of every matching edge, CC contains no other vertices; in other words, CC contains no unmatched vertex. Suppose otherwise that there is an unmatched vertex v∈Cv\in C. If v∈Xv\in X, then necessarily v∈U⊆Zv\in U\subseteq Z, contradicting the construction of CC; if v∈Yv\in Y, an alternating path reaching vv is an augmenting path relative to MM, which contradicts the fact that MM is maximum by Berge's lemma. These contradictions show that no such unmatched vertex exists, and hence CC is a minimum vertex cover.

From the network-flow viewpoint, the minimum vertex cover problem is the minimum-cut problem: selecting a left vertex is equivalent to cutting its edge to the source, and selecting a right vertex is equivalent to cutting its edge to the sink. From the linear-programming viewpoint, the minimum vertex cover problem is the dual of the maximum matching problem. Thus, König's theorem can be viewed as a special case of the max-flow min-cut theorem, or, more generally, a special case of the strong duality theorem of linear programming.

Maximum Independent Set in a Bipartite Graph

The maximum independent set problem asks us to choose as many vertices as possible in an undirected graph so that no two are adjacent.

For general graphs, the following theorem holds:

Theorem

In a graph G=(V,E)G=(V,E), a vertex set C⊆VC\subseteq V is a vertex cover if and only if its complement V∖CV\setminus C is an independent set.

Proof

A vertex set CC is a vertex cover if and only if at least one endpoint of every edge in EE, say edge ee, occurs in CC, if and only if there is no edge in EE whose two endpoints both occur in V∖CV\setminus C, if and only if V∖CV\setminus C is an independent set.

Corollary

In a graph G=(V,E)G=(V,E), the sum of the sizes of a minimum vertex cover and a maximum independent set equals the number of vertices.

Therefore, just like the minimum vertex cover problem, the maximum independent set problem is NP-hard for general graphs, but can be reduced to maximum matching for bipartite graphs and solved efficiently.

Minimum Path Cover in a Directed Acyclic Graph

The minimum path cover problem asks us to choose the minimum number of simple paths in a directed graph such that every vertex occurs in exactly one path.

The minimum path cover problem is NP-hard on general directed graphs, but for directed acyclic graphs it can be reduced to maximum bipartite matching. For a DAG G=(V,E)G=(V,E), construct a bipartite graph G′=(Vin,Vout,E′)G'=(V^\text{in},V^\text{out},E') as follows:

  • For each vertex v∈Vv\in V, create an in-vertex vinv^\text{in} and an out-vertex voutv^\text{out}. Let the sets of all in-vertices and out-vertices be VinV^\text{in} and VoutV^\text{out}, respectively. They form the left and right parts of the new graph, respectively.
  • For each directed edge (u,v)∈E(u,v)\in E, create an undirected edge (uout,vin)(u^\text{out},v^\text{in}). The set of all undirected edges is E′E'.

Thus, we have the following conclusion:

Theorem

The sum of the size of a minimum path cover of the DAG G=(V,E)G=(V,E) and the size of a maximum matching of the corresponding bipartite graph G′=(Vin,Vout,E′)G'=(V^\text{in},V^\text{out},E') equals the number of vertices.

Proof

In the bipartite graph G′G', each matching M′M' corresponds to a subgraph of graph GG, namely FF, and every vertex in FF has indegree and outdegree at most one; that is, FF is a collection of pairwise vertex-disjoint paths or cycles in the directed graph GG. However, GG is assumed to be acyclic, so FF contains only disjoint paths. Conversely, each such subgraph FF yields a corresponding matching. Since the size of matching MM equals the number of vertices minus the number of paths in FF, the minimum path cover problem of GG corresponds to the maximum matching problem of G′G'.

The proof is constructive, so it is easy to construct a corresponding minimum path cover from the maximum matching obtained. This construction also shows why the reduction fails for general directed graphs: a matching in the bipartite graph may correspond to a cycle in the directed graph.

In particular, for a set XX with a partial order PP on it, construct the DAG G=(X,P)G=(X,P). Then, by Dilworth's theorem, the size of a minimum path cover of GG equals the length of its longest antichain, that is, the width of the poset (X,P)(X,P). Thus, this section in fact gives an efficient way to compute the width of any poset.

Example Problems

The difficulty in applying bipartite matching lies in constructing the graph; this section demonstrates graph-construction techniques through several examples.

Luogu P1129 Matrix Game

There is a 01 matrix. In each operation, we may swap two rows or two columns. Determine whether it is possible to make every entry on the main diagonal (from top left to bottom right) equal to 1.

Solution

Observe that if there are nn entries equal to 11, with no two of these 11s in the same row or column, a solution necessarily exists; otherwise, no solution exists. The problem is therefore reduced to finding these nn entries equal to 11.

For a particular 11, selecting this 11 in the final arrangement means that the row and column of this 11 are occupied. Thus, construct a bipartite graph with nn left vertices and nn right vertices. For every element equal to 11, add an edge between the left vertex corresponding to its row and the right vertex corresponding to its column. We can then solve a bipartite matching problem.

Code
#include <algorithm>
#include <iostream>
#include <queue>
#include <vector>
using namespace std;

int ct, n, t[100010], x, r[100010], ans, vis[100010], dis[100010];
vector<int> to[100010];
queue<int> q;

int DFS(int x) {
  if (vis[x]) {
    return 0;
  }
  vis[x] = 1;
  for (auto i : to[x]) {
    if (!r[i]) {
      r[i] = x;
      t[x] = i;
      return 1;
    }
    if (dis[r[i]] == dis[x] + 1 && DFS(r[i])) {
      r[i] = x;
      t[x] = i;
      return 1;
    }
  }
  return 0;
}

int BFS() {
  fill(vis + 1, vis + n + 1, 0);
  fill(dis + 1, dis + n + 1, 0);
  for (int i = 1; i <= n; i++) {
    if (!t[i]) {
      q.push(i);
      dis[i] = 1;
    }
  }
  int f = 0;
  for (; q.size(); q.pop()) {
    int tmp = q.front();
    for (auto i : to[tmp]) {
      if (!r[i]) {
        f = 1;
      }
      if (r[i]) {
        if (!dis[r[i]]) {
          dis[r[i]] = dis[tmp] + 1;
          q.push(r[i]);
        }
      }
    }
  }
  return f;
}

int main() {
  ios::sync_with_stdio(false);
  cin.tie(nullptr), cout.tie(nullptr);
  for (cin >> ct; ct--;) {
    cin >> n;
    for (int i = 1; i <= n; i++) {
      for (int j = 1; j <= n; j++) {
        cin >> x;
        if (x) {
          to[i].push_back(j);
        }
      }
    }
    for (; BFS();) {
      for (int i = 1; i <= n; i++) {
        if (!t[i] && DFS(i)) {
          ans++;
        }
      }
    }
    cout << (ans == n ? "Yes" : "No") << '\n';
    for (int i = 1; i <= n; i++) {
      t[i] = r[i] = 0;
      to[i].clear();
    }
    ans = 0;
  }
  return 0;
}
Gym 104427B Lawyers

There are nn lawyers, all accused of fraud. They must defend one another so that every lawyer is acquitted. These nn lawyers have mm pairs of trust relations; a trust relation (a,b)(a, b) means that aa can defend bb. Any lawyer who is defended will be acquitted, with one exception: if aa and bb defend each other, both will be convicted.

Determine whether it is possible for every lawyer to be acquitted.

Solution

For every unordered pair (a,b)(a, b), if aa can defend bb, add an edge from the unordered-pair vertex to that lawyer; conversely, add the corresponding edge for bb in the reverse direction.

Keeping only the (a,b)(a, b) pairs that are connected by an edge transforms the problem into maximum matching in a bipartite graph with mm left vertices and nn right vertices.

Code
#include <algorithm>
#include <iostream>
#include <map>
#include <queue>
#include <utility>
#include <vector>
using namespace std;

int n, k, u, v, t[200020], r[200020], ans, vis[200020], dis[200020], c;
map<pair<int, int>, int> mp;
vector<int> to[200020];
queue<int> q;

int DFS(int x) {
  if (vis[x]) {
    return 0;
  }
  vis[x] = 1;
  for (auto i : to[x]) {
    if (!r[i]) {
      r[i] = x;
      t[x] = i;
      return 1;
    }
    if (dis[r[i]] == dis[x] + 1 && DFS(r[i])) {
      r[i] = x;
      t[x] = i;
      return 1;
    }
  }
  return 0;
}

int BFS() {
  fill(vis + 1, vis + n + 1, 0);
  fill(dis + 1, dis + n + 1, 0);
  for (int i = 1; i <= n; i++) {
    if (!t[i]) {
      q.push(i);
      dis[i] = 1;
    }
  }
  int f = 0;
  for (; q.size(); q.pop()) {
    int tmp = q.front();
    for (auto i : to[tmp]) {
      if (!r[i]) {
        f = 1;
      }
      if (r[i]) {
        if (!dis[r[i]]) {
          dis[r[i]] = dis[tmp] + 1;
          q.push(r[i]);
        }
      }
    }
  }
  return f;
}

void mxf() {
  for (; BFS();) {
    for (int i = 1; i <= n; i++) {
      if (!t[i] && DFS(i)) {
        ans++;
      }
    }
  }
}

int main() {
  ios::sync_with_stdio(false);
  cin.tie(nullptr), cout.tie(nullptr);
  cin >> n >> k;
  for (int i = 1; i <= k; i++) {
    cin >> u >> v;
    if (mp.find({u, v}) == mp.end()) {
      mp[{u, v}] = mp[{v, u}] = ++c;
    }
    to[v].push_back({mp[{u, v}]});
  }
  mxf();
  cout << (ans == n ? "YES" : "NO") << '\n';
  ans = 0;
  return 0;
}
Codeforces 1404E Bricks

Use bricks of size 1×x1 \times x to exactly cover an n×mn \times m grid; bricks may be rotated, and some cells cannot be covered.

Solution

Consider how the final arrangement is formed:

First cover every coverable cell with a 1×11 \times 1 brick. A 1×x1 \times x brick can be formed by repeatedly merging xx consecutive 1×11 \times 1 bricks in the same row, a row merge. Similarly, an x×1x \times 1 brick can be formed by repeatedly merging xx consecutive 1×11 \times 1 bricks in the same column, a column merge.

Clearly, one row merge and one column merge cannot involve the same brick, and the more merges we perform, the fewer bricks remain. Therefore, take row merges as the left vertices and column merges as the right vertices, and use the conflicts described above as edges to construct a bipartite graph. The original problem then becomes a maximum independent set problem in a bipartite graph.

Code
#include <algorithm>
#include <iostream>
#include <queue>
#include <vector>
using namespace std;

int n, m, belr[220][220], beld[220][220], dcnt, rcnt, vis[100010], dis[100010],
    t[100010], r[100010], cnt;
char c[220][220];
vector<int> to[100010];
queue<int> q;

int DFS(int x) {
  if (vis[x]) {
    return 0;
  }
  vis[x] = 1;
  for (auto i : to[x]) {
    if (!r[i]) {
      r[i] = x;
      t[x] = i;
      return 1;
    }
    if (dis[r[i]] == dis[x] + 1 && DFS(r[i])) {
      r[i] = x;
      t[x] = i;
      return 1;
    }
  }
  return 0;
}

int BFS() {
  fill(vis + 1, vis + rcnt + 1, 0);
  fill(dis + 1, dis + rcnt + 1, 0);
  for (int i = 1; i <= rcnt; i++) {
    if (!t[i]) {
      q.push(i);
      dis[i] = 1;
    }
  }
  int f = 0;
  for (; q.size(); q.pop()) {
    int tmp = q.front();
    for (auto i : to[tmp]) {
      if (!r[i]) {
        f = 1;
      }
      if (r[i]) {
        if (!dis[r[i]]) {
          dis[r[i]] = dis[tmp] + 1;
          q.push(r[i]);
        }
      }
    }
  }
  return f;
}

int solve() {
  int rt = 0;
  for (; BFS();) {
    for (int i = 1; i <= rcnt; i++) {
      if (!t[i] && DFS(i)) {
        rt++;
      }
    }
  }
  return rt;
}

int main() {
  ios::sync_with_stdio(false);
  cin.tie(nullptr), cout.tie(nullptr);
  cin >> n >> m;
  for (int i = 1; i <= n; i++) {
    for (int j = 1; j <= m; j++) {
      cin >> c[i][j];
    }
  }
  for (int i = 1; i <= n; i++) {
    for (int j = 1; j <= m; j++) {
      if (c[i][j] == '#') {
        cnt++;
        if (c[i + 1][j] == '#') {
          beld[i][j] = ++dcnt;
        }
        if (c[i][j + 1] == '#') {
          belr[i][j] = ++rcnt;
        }
      }
    }
  }
  for (int i = 1; i <= n; i++) {
    for (int j = 1; j <= m; j++) {
      if (c[i][j] == '#') {
        if (c[i - 1][j] == '#' && c[i][j - 1] == '#') {
          to[belr[i][j - 1]].push_back(beld[i - 1][j]);
        }
        if (c[i + 1][j] == '#' && c[i][j + 1] == '#') {
          to[belr[i][j]].push_back(beld[i][j]);
        }
        if (c[i + 1][j] == '#' && c[i][j - 1] == '#') {
          to[belr[i][j - 1]].push_back(beld[i][j]);
        }
        if (c[i - 1][j] == '#' && c[i][j + 1] == '#') {
          to[belr[i][j]].push_back(beld[i - 1][j]);
        }
      }
    }
  }
  cout << cnt - rcnt - dcnt + solve() << '\n';
  return 0;
}
Codeforces 1139E - Maximize Mex

There are mm multisets, each containing nn elements. In each operation, delete one element from one of the multisets, then query the maximum mex⁡\operatorname{mex} obtainable by selecting at most one element from each multiset.

Solution

First consider how to solve the problem when no elements have been deleted.

For each multiset, create a new vertex; for each possible answer, create a new vertex. Then, for a multiset corresponding to vertex lil_i, for each element aa, add an edge from lil_i to rar_a. This simplified version becomes a maximum bipartite matching problem.

Now add back the deletion operations. We find that this is intractable: deleting one edge may cause the matching to change drastically, and the complexity is unacceptable. Instead, reverse the process: add one edge at a time, then continue forward and augment again. Therefore, this problem can only be solved with the Kuhn algorithm.

Code
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;

struct node {
  int u, v;
} arr[5050];

int n, m, t[5050], r[5050], d, ot[5050], kil[5050], vis[5050], ans, out[5050];
vector<int> to[5050];

int DFS(int x) {
  if (vis[x]) {
    return 0;
  }
  vis[x] = 1;
  for (auto i : to[x]) {
    if (r[i] == -1) {
      r[i] = x;
      t[x] = i;
      return 1;
    }
    if (DFS(r[i])) {
      r[i] = x;
      t[x] = i;
      return 1;
    }
  }
  return 0;
}

int main() {
  cin >> n >> m;
  for (int i = 1; i <= n; i++) {
    cin >> arr[i].u;
    if (arr[i].u > m) {
      arr[i].u = m + 1;
    }
  }
  for (int i = 1; i <= n; i++) {
    cin >> arr[i].v;
  }
  cin >> d;
  for (int i = 1; i <= d; i++) {
    cin >> ot[i];
    kil[ot[i]] = 1;
  }
  for (int i = 1; i <= n; i++) {
    if (!kil[i]) {
      to[arr[i].u].push_back(arr[i].v);
    }
  }
  fill(r + 1, r + m + 1, -1);
  for (; ans <= m;) {
    fill(vis, vis + m + 2, 0);
    if (DFS(ans)) {
      ans++;
    } else {
      break;
    }
  }
  out[d] = ans;
  for (int i = d; i > 1; i--) {
    to[arr[ot[i]].u].push_back(arr[ot[i]].v);
    for (; ans <= m;) {
      fill(vis, vis + m + 2, 0);
      if (DFS(ans)) {
        ans++;
      } else {
        break;
      }
    }
    out[i - 1] = ans;
  }
  for (int i = 1; i <= d; i++) {
    cout << out[i] << '\n';
  }
  return 0;
}
Luogu P3355 - Knight Coexistence Problem

There is an n×nn \times n chessboard, some positions cannot hold pieces. What is the maximum number of knights that can be placed so that no two knights attack each other?

Solution

Observe that the entire board can be colored so that no two squares of the same color are adjacent; then a knight can attack only a square of the opposite color.

Then we can directly solve a maximum independent set problem in a bipartite graph.

Code
#include <algorithm>
#include <iostream>
#include <queue>
#include <vector>
using namespace std;

const int kD[8][2] = {{-2, -1}, {-1, -2}, {1, -2}, {2, -1},
                      {2, 1},   {1, 2},   {-1, 2}, {-2, 1}};

int n, m, ib;
int vis[200020], dis[200020], t[200020], r[200020], ans, u, v, cnta,
    x[220][220], cl[220][220], idx, bel[220][220];
vector<int> to[200020];
queue<int> q;

int DFS(int x) {
  if (vis[x]) {
    return false;
  }
  vis[x] = true;
  for (auto i : to[x]) {
    if (!r[i]) {
      r[i] = x;
      t[x] = i;
      return true;
    }
    if (dis[r[i]] == dis[x] + 1 && DFS(r[i])) {
      r[i] = x;
      t[x] = i;
      return true;
    }
  }
  return false;
}

int BFS() {
  fill(vis + 1, vis + cnta + 1, false);
  fill(dis + 1, dis + cnta + 1, 0);
  for (int i = 1; i <= cnta; i++) {
    if (!t[i]) {
      q.push(i);
      dis[i] = 1;
    }
  }
  int f = 0;
  for (; q.size(); q.pop()) {
    int tmp = q.front();
    for (auto i : to[tmp]) {
      if (!r[i]) {
        f = 1;
      }
      if (r[i]) {
        if (!dis[r[i]]) {
          dis[r[i]] = dis[tmp] + 1;
          q.push(r[i]);
        }
      }
    }
  }
  return f;
}

void din() {
  for (; BFS();) {
    for (int i = 1; i <= cnta; i++) {
      if (!t[i] && DFS(i)) {
        ans++;
      }
    }
  }
}

int main() {
  ios::sync_with_stdio(false);
  cin.tie(nullptr), cout.tie(nullptr);
  cin >> n >> m;
  for (int i = 1; i <= m; i++) {
    cin >> u >> v;
    x[u][v] = true;
  }
  cl[1][1] = 1;
  if (!x[1][1]) {
    bel[1][1] = ++idx;
  }
  for (int i = 2; i <= n; i++) {
    cl[1][i] = cl[1][i - 1] ^ 1;
    if (!x[1][i] && cl[1][i]) {
      bel[1][i] = ++idx;
    } else {
      if (!x[1][i]) {
        bel[1][i] = ++ib;
      }
    }
  }
  for (int i = 2; i <= n; i++) {
    for (int j = 1; j <= n; j++) {
      cl[i][j] = cl[i - 1][j] ^ 1;
      if (!x[i][j] && cl[i][j]) {
        bel[i][j] = ++idx;
      } else {
        if (!x[i][j]) {
          bel[i][j] = ++ib;
        }
      }
    }
  }
  for (int i = 1; i <= n; i++) {
    for (int j = 1; j <= n; j++) {
      if (!x[i][j]) {
        cnta += cl[i][j];
        for (int k = 0; k < 8; k++) {
          if (i + kD[k][0] > 0 && j + kD[k][1] > 0 &&
              bel[i + kD[k][0]][j + kD[k][1]] &&
              !x[i + kD[k][0]][j + kD[k][1]]) {
            if (cl[i + kD[k][0]][j + kD[k][1]]) {
              to[bel[i + kD[k][0]][j + kD[k][1]]].push_back(bel[i][j]);
            } else {
              to[bel[i][j]].push_back(bel[i + kD[k][0]][j + kD[k][1]]);
            }
          }
        }
      }
    }
  }
  din();
  cout << n * n - m - ans << '\n';
  return 0;
}

Exercises

References

Footnotes

  1. Bast, Holger; Mehlhorn, Kurt; Schäfer, Guido; Tamaki, Hisao (2006), "Matching algorithms are fast in sparse random graphs", Theory of Computing Systems, 39 (1): 3–14. ↩

This content comes from OI Wiki: Maximum Bipartite Matching. See the original for authors and revision history. AIOJ has adapted the formatting, in-site links, and resource paths.

Content is shared under CC BY-SA 4.0 and SATA license; additional terms are governed by the original notice. Thanks to the OI Wiki authors and contributors; per the SATA terms, please visit the OI Wiki repository and star it to show your support.