給定 n × n 棋盤,'.' 表示可放置位置,'X' 表示牆壁。尋找最多能放置多少個「車」(象棋車,可沿行列直線攻擊),使任意兩車互不攻擊。車的攻擊被牆壁阻擋。
左側點集 = 行(1~n),右側點集 = 列(1~n)。每個 '.' 位置 (x, y) 對應一條邊 x → y。最大匹配數即為答案。
牆壁將行/列分割成多個線段。兩車互不攻擊 ⇔ 它們所在的行線段與列線段不重疊。因此:
X 重新編號)X 重新編號)'.' 位置連接其所屬的行線段 ID 和列線段 ID// 行線段編號
for (int i = 0; i < n; i++) {
int id = 0;
for (int j = 0; j < n; j++) {
if (board[i][j] == 'X') id = 0;
else if (id == 0) id = ++rowSegCnt;
rowId[i][j] = id;
}
}
// 列線段編號
for (int j = 0; j < n; j++) {
int id = 0;
for (int i = 0; i < n; i++) {
if (board[i][j] == 'X') id = 0;
else if (id == 0) id = ++colSegCnt;
colId[i][j] = id;
}
}
vectorG[MAXN]; int match[MAXN]; bool vis[MAXN]; bool dfs(int u) { for (int v : G[u]) { if (!vis[v]) { vis[v] = true; if (match[v] == 0 || dfs(match[v])) { match[v] = u; return true; } } } return false; } int maxMatching() { int ans = 0; memset(match, 0, sizeof(match)); for (int u = 1; u <= rowSegCnt; u++) { memset(vis, 0, sizeof(vis)); if (dfs(u)) ans++; } return ans; }
'.' 其行線段 ID 和列線段 IDG[rowId[i][j]].push_back(colId[i][j])O(n²)O(n²) 邊數 ≤ 空格數O(V × E),實際極快;HK 算法 O(√V × E) 更優n ≤ 100 甚至更大規模此模型適用於所有「網格放置不相互攻擊棋子且有障礙物」的問題,如放國王、放主教(需按對角線分段)等。