|
|
#include <bits/stdc++.h>
|
|
|
using namespace std;
|
|
|
const int N = 10010, M = 40010;
|
|
|
|
|
|
int n, m;
|
|
|
|
|
|
int dx[] = {-1, 0, 1, 0}; // 上右下左
|
|
|
int dy[] = {0, 1, 0, -1}; // 上右下左
|
|
|
|
|
|
int g[N]; // 一维的转换后表示,如果手欠,想写成二维的,一定要注意不能写N,要写110,否则会SE,不要问我是怎么知道的!
|
|
|
|
|
|
// 链式前向星
|
|
|
int e[M], h[N], idx, w[M], ne[M];
|
|
|
void add(int a, int b, int c = 0) {
|
|
|
e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx++;
|
|
|
}
|
|
|
|
|
|
// 匈牙利算法模板
|
|
|
int match[N], st[N];
|
|
|
int find(int u) {
|
|
|
for (int i = h[u]; ~i; i = ne[i]) {
|
|
|
int v = e[i];
|
|
|
if (st[v]) continue;
|
|
|
st[v] = 1;
|
|
|
if (match[v] == -1 || find(match[v])) {
|
|
|
match[v] = u;
|
|
|
return 1;
|
|
|
}
|
|
|
}
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
int main() {
|
|
|
memset(h, -1, sizeof h); // 初始化链式前向星
|
|
|
memset(match, -1, sizeof match); // 初始化匈牙利算法的匹配标识数组
|
|
|
|
|
|
scanf("%d %d", &n, &m);
|
|
|
|
|
|
while (m--) {
|
|
|
int a, b;
|
|
|
scanf("%d%d", &a, &b);
|
|
|
// 因为要做坐标变换,需要下标从0开始,本题下标从1开始,采用减一大法
|
|
|
a--, b--;
|
|
|
g[a * n + b] = 1;
|
|
|
}
|
|
|
|
|
|
for (int i = 0; i < n; i++)
|
|
|
for (int j = 0; j < n; j++) {
|
|
|
if (g[i * n + j]) continue; // 出发点有障碍物不可以
|
|
|
if ((i + j) % 2 == 0) continue; // 出发点是黑色点不可以
|
|
|
|
|
|
for (int k = 0; k < 4; k++) {
|
|
|
int tx = i + dx[k], ty = j + dy[k];
|
|
|
if (g[tx * n + ty]) continue; // 目标点有障碍物
|
|
|
if (tx < 0 || tx == n || ty < 0 || ty == n) continue; // 目标点出界
|
|
|
add(i * n + j, tx * n + ty); // 加边
|
|
|
}
|
|
|
}
|
|
|
|
|
|
int res = 0;
|
|
|
for (int i = 0; i < n; i++)
|
|
|
for (int j = 0; j < n; j++)
|
|
|
if ((i + j) % 2 == 1) {
|
|
|
memset(st, 0, sizeof st);
|
|
|
res += find(i * n + j);
|
|
|
}
|
|
|
|
|
|
printf("%d\n", res);
|
|
|
return 0;
|
|
|
} |