首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> C++ 入門

UVALive 6525 Attacking Rooks - 二分圖最大匹配經典建模

     編輯:C++ 入門

UVALive 6525 Attacking Rooks - 二分圖最大匹配經典建模

題目大意

給定 n × n 棋盤,'.' 表示可放置位置,'X' 表示牆壁。尋找最多能放置多少個「車」(象棋車,可沿行列直線攻擊),使任意兩車互不攻擊。車的攻擊被牆壁阻擋。

核心建模思路:二分圖最大匹配

無牆壁情況

左側點集 = 行(1~n),右側點集 = 列(1~n)。每個 '.' 位置 (x, y) 對應一條邊 x → y。最大匹配數即為答案。

有牆壁情況 - 關鍵洞察

牆壁將行/列分割成多個線段。兩車互不攻擊 ⇔ 它們所在的行線段與列線段不重疊。因此:

  • 左側點集 = 所有行線段(從左到右掃描,遇 X 重新編號)
  • 右側點集 = 所有列線段(從上到下掃描,遇 X 重新編號)
  • 每個 '.' 位置連接其所屬的行線段 ID 和列線段 ID

線段編號算法(DP 預處理)

// 行線段編號
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;
    }
}

匈牙利算法 / HK 算法求最大匹配

vector G[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;
}

完整解題框架

  1. 讀入棋盤
  2. 掃描賦予每個 '.' 其行線段 ID 和列線段 ID
  3. 建圖:G[rowId[i][j]].push_back(colId[i][j])
  4. 跑最大匹配,輸出匹配數

複雜度分析

  • 預處理:O(n²)
  • 建圖:O(n²) 邊數 ≤ 空格數
  • 匈牙利算法:O(V × E),實際極快;HK 算法 O(√V × E) 更優
  • 總體輕鬆通過 n ≤ 100 甚至更大規模

經典變體延伸

此模型適用於所有「網格放置不相互攻擊棋子且有障礙物」的問題,如放國王、放主教(需按對角線分段)等。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved