棋盘覆盖
棋盘覆盖
https://ac.nowcoder.com/acm/problem/51272
题意:
给一个nn的棋盘, 棋盘上有m个障碍,要求用12的多米诺骨牌进行掩盖。且任意两张骨牌都不重叠,障碍上不能有骨牌。
思路:
- 1*2的骨牌且骨牌不能有重叠,这个性质很容易想到二分图。
- 怎样建这个图呢?
- 将棋盘上的点提出来, 每个点与它相邻的四个点进行连边操作,这样见图就完成了
- 建图似乎有点麻烦,那就简化一下,我们将每个点与它的相邻上边和左边的点连边,至于他的右边和下边的点,在后面的连边操作中都加进去, 这样就可以不重不漏了.
- 建图完成就是求二分图最他匹配板子了没什么好说的了
代码:
#include <iostream> #include <algorithm> #include <cstring> #include <vector> using namespace std; const int maxn = 2e5 + 7; int h[maxn], e[maxn << 1], ne[maxn << 1], cnt; int match[maxn], vis[maxn]; int over, star; void add(int u, int v) { e[cnt] = v; ne[cnt] = h[u]; h[u] = cnt ++; } bool dfs(int u) { for (int i = h[u]; ~i; i = ne[i]) { int v = e[i]; if (!vis[v]) { vis[v] = 1; if (match[v] == 0 || dfs(match[v])) { match[v] = u; return true; } } } return false; } int tem[maxn], arr[200][200]; int main () { int n, m; scanf ("%d%d", &n, &m); for (int i = 0; i <= n; i ++ ) h[i] = -1; cnt = 0; memset(match, 0, sizeof match); memset(arr, 0, sizeof arr); memset(tem, 0, sizeof tem); for (int i = 0, x, y; i < m; i ++ ) { scanf ("%d%d", &x, &y); arr[x][y] = 1; } for (int i = 1; i <= n; i ++ ) { for (int j = 1; j <= n; j ++ ) { if (!arr[i][j]) { tem[(i-1)*n+j] = 1; // cout << (i-1)*n+j << endl; if (i - 1 >= 1 && !arr[i-1][j]) { add((i-2)*n+j, (i-1)*n+j); add((i-1)*n+j, (i-2)*n+j); // cout << (i-2)*n+j << " " << (i-1)*n+j<<endl; } if (j - 1 >= 1 && !arr[i][j-1]) { add((i-1)*n+j-1, (i-1)*n+j); add((i-1)*n+j, (i-1)*n+j-1); // cout << (i-1)*n+j-1 << " " << (i-1)*n+j<<endl; } } } } int res = 0; for (int i = 1; i <= n*n; i ++ ) { if (tem[i]) { memset(vis, 0, sizeof vis); if (dfs(i)) res++; } } printf ("%d\n", res/2);// 因为我们建的是无向图所以匹配出来的是原来的二倍这个应该不用多解释吧 return 0; }