二分图的最大匹配问题。
每个格子的横坐标和纵坐标之和为奇数或偶数,和为奇数的格子只可能与和为偶数的格子相邻,所以将和为奇数的格子作为二分图的一边,将和为偶数的格子作为二分图的另一边,如果两个空地格子相邻,则在两者之间连线。然后计算二分图的最大匹配数即可。
#include <cstdio>
#include <cstring>
#include <cmath>
const int MAXN = 105;
int mp[MAXN][MAXN]; //地图,0表示空地,1表示池塘
int line[MAXN][MAXN]; //二分图的连线
int vis[MAXN], match[MAXN]; //访问情况,匹配情况
int num; //小正方形空地的数量
int total; //最大匹配数
struct rectangle //小正方形空地
{
int x;
int y;
}r[MAXN * MAXN];
//查找从x出发的增广路径
bool find(int x)
{
for (int i = 0; i < num; i++)
{
if (!vis[i] && line[x][i])
{
vis[i] = 1;
if (match[i] == -1 || find(match[i]))
{
match[i] = x;
return true;
}
}
}
return false;
}
//查找二分图的最大匹配数
void maxMatch()
{
total = 0;
memset(match, -1, sizeof(match));
for (int i = 0; i < num; i++)
{
memset(vis, 0, sizeof(vis));
if (find(i))
++total;
}
}
int main()
{
int N, M;
while (scanf("%d%d", &N, &M))
{
if (N == 0 && M == 0)
break;
memset(mp, 0, sizeof(mp));
int K;
scanf("%d", &K);
int u, v;
while (K--) //输入池塘位置
{
scanf("%d%d", &u, &v);
mp[u][v] = 1;
}
num = 0;
for (int i = 1; i <= N; i++) //标记空地位置
{
for (int j = 1; j <= M; j++)
{
if (mp[i][j] == 0)
{
r[num].x = i;
r[num].y = j;
++num;
}
}
}
memset(line, 0, sizeof(line));
for (int i = 0; i < num; i++)
{
for (int j = i + 1; j < num; j++)
{
if ((abs(r[i].x - r[j].x) == 1 && r[i].y == r[j].y) || (abs(r[i].y - r[j].y) == 1 && r[i].x == r[j].x))
{
if ((r[i].x + r[i].y) % 2 == 0)
line[j][i] = 1;
else
line[i][j] = 1;
}
}
}
maxMatch();
printf("%d\n", total);
for (int i = 0; i < num; i++)
{
if (match[i] != -1)
{
printf("(%d,%d)--(%d,%d)\n", r[i].x, r[i].y, r[match[i]].x, r[match[i]].y);
}
}
printf("\n");
}
return 0;
}
继续加油。