HDU 1150 要求找出二分圖的最小點覆蓋數。根據Kőnig 定理:
二分圖的最小點覆蓋數 = 最大匹配數
因此問題轉化為求二分圖最大匹配。
使用 DFS 基礎的匈牙利算法尋找增廣路徑,時間複雜度 O(VE),適用於本題資料範圍。
import java.io.*;
import java.util.*;
class Edge {
int to, next;
}
class Solution {
static Scanner in = new Scanner(System.in);
static PrintWriter out = new PrintWriter(System.out);
int n, m; // 兩邊頂點數
int[] match = new int[1111]; // 右側頂點匹配的左側頂點
Edge[] edges = new Edge[1111];
int[] head = new int[1111];
int[] vis = new int[1111];
int tot = 0;
void init() {
tot = 0;
Arrays.fill(match, -1);
Arrays.fill(head, -1);
}
void addEdge(int u, int v) {
edges[tot] = new Edge();
edges[tot].to = v;
edges[tot].next = head[u];
head[u] = tot++;
}
// DFS 尋找增廣路徑
boolean dfs(int u) {
for (int i = head[u]; i != -1; i = edges[i].next) {
int v = edges[i].to;
if (vis[v] == 1) continue;
vis[v] = 1;
if (match[v] == -1 || dfs(match[v])) {
match[v] = u;
return true;
}
}
return false;
}
void solve() {
while (in.hasNext()) {
init();
n = in.nextInt();
if (n == 0) break;
m = in.nextInt();
int k = in.nextInt();
for (int i = 1; i <= k; i++) {
int a = in.nextInt(); // 機器編號(忽略)
int b = in.nextInt(); // 左側頂點
int c = in.nextInt(); // 右側頂點
addEdge(b, c);
}
int ans = 0;
for (int i = 1; i <= n; i++) {
Arrays.fill(vis, 0);
if (dfs(i)) ans++;
}
out.println(ans);
}
out.close();
}
}
public class Main {
public static void main(String[] args) {
new Solution().solve();
}
}
| 陣列 | 用途 |
|---|---|
head[] | 鄰接表頭指標 |
edges[] | 邊資訊(終點、下一條邊索引) |
match[] | 右側頂點對應的左側匹配頂點 |
vis[] | DFS 當輪訪問標記 |
Arrays.fill(vis, 0)while (in.hasNext()) 迴圈處理,遇到 n=0 結束a b c,其中 a 為機器編號(題目背景資訊,解題時忽略)若資料範圍擴大(V ~ 10⁵),可改用 Hopcroft-Karp 算法,時間複雜度 O(√V × E),利用 BFS 分層 + DFS 尋找多條最短增廣路徑並行推進。
HDU 1150 是二分圖最大匹配的經典應用。掌握 Kőnig 定理與匈牙利算法 DFS 實作,是解決此類問題的核心技能。Java 實作需注意輸入輸出效率,使用 Scanner + PrintWriter 並關閉緩衝區足以應對本題規模。