Bipartite Matching
Bipartite Matching Algorithms: Kuhn's Algorithm และ Hopcroft-Karp
Bipartite Matching
Bipartite Matching คือการหา maximum matching ใน bipartite graph
Kuhn’s Algorithm (Hungarian Algorithm for Matching)
Simple augmenting path algorithm ที่หา maximum matching ใน
Implementation
class BipartiteMatching {
int n, m; // n = left size, m = right size
vector<vector<int>> adj; // adjacency list for left side
vector<int> match; // match[right_node] = left_node (or -1)
vector<bool> used;
bool dfs(int v) {
for (int to : adj[v]) {
if (!used[to]) {
used[to] = true;
if (match[to] == -1 || dfs(match[to])) {
match[to] = v;
return true;
}
}
}
return false;
}
public:
BipartiteMatching(int n, int m) : n(n), m(m), adj(n), match(m, -1), used(m) {}
void addEdge(int u, int v) {
adj[u].push_back(v);
}
int maxMatching() {
int result = 0;
for (int v = 0; v < n; v++) {
fill(used.begin(), used.end(), false);
if (dfs(v)) {
result++;
}
}
return result;
}
// Get the matching pairs (left, right)
vector<pair<int, int>> getMatching() {
vector<pair<int, int>> result;
for (int i = 0; i < m; i++) {
if (match[i] != -1) {
result.push_back({match[i], i});
}
}
return result;
}
};
Hopcroft-Karp Algorithm
Faster algorithm ที่หา maximum matching ใน
Implementation
class HopcroftKarp {
int n, m;
vector<vector<int>> adj;
vector<int> matchL, matchR; // matchL[left] = right, matchR[right] = left
vector<int> dist;
bool bfs() {
queue<int> q;
for (int u = 0; u < n; u++) {
if (matchL[u] == -1) {
dist[u] = 0;
q.push(u);
} else {
dist[u] = INT_MAX;
}
}
bool found = false;
while (!q.empty()) {
int u = q.front();
q.pop();
for (int v : adj[u]) {
int next = matchR[v];
if (next == -1) {
found = true;
} else if (dist[next] == INT_MAX) {
dist[next] = dist[u] + 1;
q.push(next);
}
}
}
return found;
}
bool dfs(int u) {
for (int v : adj[u]) {
int next = matchR[v];
if (next == -1 || (dist[next] == dist[u] + 1 && dfs(next))) {
matchL[u] = v;
matchR[v] = u;
return true;
}
}
dist[u] = INT_MAX;
return false;
}
public:
HopcroftKarp(int n, int m) : n(n), m(m), adj(n), matchL(n, -1), matchR(m, -1), dist(n) {}
void addEdge(int u, int v) {
adj[u].push_back(v);
}
int maxMatching() {
int result = 0;
while (bfs()) {
for (int u = 0; u < n; u++) {
if (matchL[u] == -1 && dfs(u)) {
result++;
}
}
}
return result;
}
vector<pair<int, int>> getMatching() {
vector<pair<int, int>> result;
for (int u = 0; u < n; u++) {
if (matchL[u] != -1) {
result.push_back({u, matchL[u]});
}
}
return result;
}
};
ทฤษฎีที่เกี่ยวข้อง
Konig’s Theorem
ใน bipartite graph:
Hall’s Theorem
Bipartite graph มี matching ที่ saturates ทั้งหมด ก็ต่อเมื่อ:
โดยที่ คือ neighbors ของ
หา Minimum Vertex Cover
vector<int> minVertexCover() {
// Run max matching first
maxMatching();
// BFS from unmatched left vertices
vector<bool> visitedL(n, false), visitedR(m, false);
queue<int> q;
for (int u = 0; u < n; u++) {
if (matchL[u] == -1) {
q.push(u);
visitedL[u] = true;
}
}
while (!q.empty()) {
int u = q.front();
q.pop();
for (int v : adj[u]) {
if (!visitedR[v]) {
visitedR[v] = true;
if (matchR[v] != -1 && !visitedL[matchR[v]]) {
visitedL[matchR[v]] = true;
q.push(matchR[v]);
}
}
}
}
// Vertex cover: unvisited left + visited right
vector<int> cover;
for (int u = 0; u < n; u++) {
if (!visitedL[u]) cover.push_back(u); // left side
}
for (int v = 0; v < m; v++) {
if (visitedR[v]) cover.push_back(n + v); // right side
}
return cover;
}
ประยุกต์ใช้งาน
1. Job Assignment
แต่ละคนทำได้ 1 งาน, แต่ละงานต้องการ 1 คน
int maxJobs(int workers, int jobs, vector<pair<int,int>>& canDo) {
BipartiteMatching bm(workers, jobs);
for (auto& [w, j] : canDo) {
bm.addEdge(w, j);
}
return bm.maxMatching();
}
2. Domino Covering
นับจำนวน dominoes ที่วางได้บน grid (cells เป็น bipartite โดย checkerboard pattern)
3. Independent Set in Bipartite Graph
4. Edge Cover
(ถ้าไม่มี isolated vertices)
Complexity Comparison
| Algorithm | Time | Space |
|---|---|---|
| Kuhn | ||
| Hopcroft-Karp | ||
| Max Flow (Dinic) |
Tips
- Kuhn’s algorithm ง่ายต่อการ implement และเร็วพอสำหรับกรณีส่วนใหญ่
- Hopcroft-Karp เร็วกว่าสำหรับ large sparse graphs
- Max Flow ยืดหยุ่นกว่า - ใช้ได้กับ weighted matching (ใช้ MCMF)
- Vertex ordering ใน Kuhn อาจมีผลต่อ performance