此题非常好,匹配 建图的经典之作!棋盘分割,又是启发其他题目引领想法的好题目!重要的还学到二分集合无界限的处理方法!
// Created : 2012-06-06
// Author : aclay
#include <iostream>
#include <string>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <queue>
#include <algorithm>
using namespace std;
const int N = 35*35;
int map[N][N];
int vis[N][N];
int id[N][N];
int n, m, k;
int nx, ny;
int mk[N];
int cx[N], cy[N];
bool dfs(int u) {
int v;
for(v = 1; v <= ny; v++) {
if(map[u][v] && !mk[v]) {
mk[v] = 1; // /// 标记 v 已经被使用了,在这次 dfs 寻找 增广路 中
if(cy[v] == -1 || dfs(cy[v])) { // // 如果v没有匹配,或者如果v已经匹配了,但从y[v]出发可以找到一条增广路
cy[v] = u;
cx[u] = v;
return true;
}
}
}
return false;
}
int MaxMatch() {
int res = 0;
memset(cx, -1, sizeof(cx));
memset(cy, -1, sizeof(cy));
for(int i = 1; i <= nx; i++) {
if(cx[i] == -1) { //从每个未盖点出发进行寻找增广路
memset(mk, 0, sizeof(mk));
res += dfs(i);
}
}
return res;
}
int main() {
int i, j, x, y;
scanf("%d%d%d", &m, &n, &k);
memset(map, 0, sizeof(map));
memset(vis, 0, sizeof(vis));
for(i = 0; i < k; i++) {
scanf("%d%d", &y, &x);
vis[x][y] = 1; // 黑洞
}
int t = 0;
for(i = 1; i <= m; i++) {
for(j = 1; j <= n; j++) {
if(!vis[i][j]) {
id[i][j] = ++t; // 非黑洞格子标号
}
}
}
for(i = 1; i <= m; i++) {
for(j = 1; j <= n; j++) { // 建图
if(!vis[i][j]) {
if(i > 1 && !vis[i-1][j]) {
map[id[i][j]][id[i-1][j]] = 1;
}
if(j > 1 && !vis[i][j-1]) {
map[id[i][j]][id[i][j-1]] = 1;
}
if(i+1 <= m && !vis[i+1][j]) {
map[id[i][j]][id[i+1][j]] = 1;
}
if(j+1 <= n && !vis[i][j+1]) {
map[id[i][j]][id[i][j+1]] = 1;
}
}
}
}
nx = ny = t;
int num = MaxMatch();
if(num + k == n*m) {
printf("YES\n");
}
else printf("NO\n");
system("pause");
return 0;
}