1. 程式人生 > 實用技巧 >U64949 棋盤覆蓋(二分圖)

U64949 棋盤覆蓋(二分圖)

https://ac.nowcoder.com/acm/contest/1062/B

【題目】

給出一張n×n(n≤100)的國際象棋棋盤,其中被刪除了一些點,問可以使用多少1*2的多米諾骨牌進行掩蓋。

【題意】

題意簡單,不做多說明,多米諾骨牌可以理解為長方形的方塊。

【題解】

仔細一想,可以發現能用二分圖來做。即可以把每個位置的點進行重新編號,相鄰的兩點具有不同的性質。比如說在2×2的圖內第一個點\((1,1)\)標記為1,它是奇數,那麼與它相鄰的\((1,2)(1,2)\)就要標記成偶數。又比如在3×3的圖內的點\((2,2)\)為奇數,那麼\((1,2),(2,1)(2,3),(3,2)\)的點就要標記為偶數。然後兩兩建邊,奇數點->偶數點 or 偶數點->奇數點(當然如果是被刪除的點,則不能建邊)。最後對 偶數點 or 奇數點 跟 奇數點 or 偶數點 進行二分圖匹配即可。

時間複雜度:\(O(N^2)\)

#include<bits/stdc++.h>
using namespace std;
const int N = 110;
const int dx[] = { 0,1,0,-1 };
const int dy[] = { 1,0,-1,0 };
int n, m, ans, f[N * N];
bool b[N][N], v[N * N];
vector<int>e[N * N];

bool dfs(int x) {
    for (unsigned int i = 0; i < e[x].size(); i++) {
        int y = e[x][i];
        if (v[y]) continue;
        v[y] = 1;
        if (f[y] == -1 || dfs(f[y])) {
            f[y] = x;return 1;
        }
    }
    return 0;
}

int main() {
    //freopen("in.txt", "r", stdin);
    ios::sync_with_stdio(false), cin.tie(0);
    cin >> n >> m;
    while (m--) {
        int x, y; cin >> x >> y;
        b[x - 1][y - 1] = 1;
    }
    for (int i = 0; i < n; i++)
		for (int j = 0; j < n; j++)
			if (!b[i][j])
				for (int k = 0; k < 4; k++) {
					int x = i + dx[k], y = j + dy[k];
					if (x >= 0 && x < n && y >= 0 && y < n && !b[x][y]) {
						e[i*n+j].push_back(x * n + y);
						e[x*n+y].push_back(i * n + j);
					}
				}
    memset(f, -1, sizeof(f));
    for (int i = 0; i < n; i++)
        for (int j = 0; j < n; j++) {
            if ((i ^ j) & 1) continue;
            memset(v, 0, sizeof(v));
            ans += dfs(i * n + j);
        }
    cout << ans << endl;
}