http://poj.org/problem?id=2446
这道题,十分的妙啊。我一开始死活想不出到底怎么做,这竟然是二分图???我往这方面想也没有结果。后来在网上看到了二分图常用的建图技巧,我看到了网格图的建图方法。方法就是染色。就按照样例来说
大概就是这样,然后跑一遍最大匹配即可。求到最大匹配后乘以2就是可以填补多少个空格。如果这个个数和空格个数不相等,那么就是无法完全填满,否则就可以完全填满。
代码如下:
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int MAXN = 520;
int uN, vN;
int G[MAXN][MAXN];
int tmp[MAXN][MAXN];
int linker[MAXN];
bool used[MAXN];
bool dfs(int u)
{
int v;
for(v = 1; v <= vN; v++)
if(G[u][v] && !used[v])
{
used[v] = true;
if(linker[v] == -1 || dfs(linker[v]))
{
linker[v] = u;
return true;
}
}
return false;
}
int hungary()
{
int res = 0;
int u;
memset(linker, -1, sizeof(linker));
for(u = 1; u <= uN; u++)
{
memset(used, 0, sizeof(used));
if(dfs(u))
res++;
}
return res;
}
int main()
{
int dir[][2] = {0,1,1,0};
int n, m, t, x, y, ans;
int cnt1 = 1, cnt2 = 1;
cin >> n >> m >> t;
ans = n * m - t;
while(t--)
{
scanf("%d%d", &x, &y);
tmp[y][x] = -1;
}
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++)
{
if(tmp[i][j] == -1)
continue;
if((i + j) % 2 == 0)
tmp[i][j] = cnt1++;
else
tmp[i][j] = cnt2++;
}
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++)
{
for(int k = 0; k < 2; k++)
{
x = i + dir[k][0];
y = j + dir[k][1];
if(x > 0 && x <= n && y > 0 && y <= m && tmp[i][j] > 0 && tmp[x][y] > 0)
{
if((i + j) % 2 == 0)
G[tmp[i][j]][tmp[x][y]] = 1;
else
G[tmp[x][y]][tmp[i][j]] = 1;
}
}
}
uN = cnt1 - 1;
vN = cnt2 - 1;
t = hungary();
if(ans == t * 2)
cout << "YES" << endl;
else
cout << "NO" << endl;
return 0;
}