思路:给你一个n * m的棋盘,有hole。问能否在不遮住hole的情况下,将棋盘全部用1 * 2的矩形覆盖。
分析图形,使用匈牙利匹配奇数坐标和偶数坐标,看是否能完全匹配即可。
#include<iostream>
#include<vector>
#include<cstring>
using namespace std;
int vis[2500], vis1[500][500], vis2[500][500], vis3[500][500], Link[2500], g[200][200];
vector<int>G[2005];
int n, m, sum;
bool Find(int u)
{
for(int i = 0; i < G[u].size(); i++)
{
int t = G[u][i];
if(!vis[t])
{
vis[t] = 1;
if( Link[t] == -1 || Find(Link[t]))
{
Link[t] = u;
return true;
}
}
}
return false;
}
int solve()
{
int cnt = 0;
memset(Link, -1, sizeof Link);
for(int i = 1; i <= sum; i++)
{
memset(vis, 0, sizeof vis);
if(G[i].size())
{
if(Find(i))
cnt++;
}
}
return cnt;
}
int main()
{
int h;
while(cin >> n >> m >> h)
{
memset(g, 0, sizeof g);
memset(vis1, 0, sizeof vis1);
memset(vis2, 0, sizeof vis2);
memset(vis3, 0, sizeof vis3);
for(int i = 1; i <= h; i++)
{
int x, y;
cin >> x >> y;
g[y][x] = 1;
}
sum = 0;
int cnt1 = 0, cnt2 = 0;
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++)
{
vis2[i][j] = ++sum;
if(g[i][j] == 0)
{
if((i + j) % 2 == 0)
cnt1++;
else cnt2++;
}
}
int T = 2;
int flag = 0;
while(T--)
{
memset(vis3, 0, sizeof vis3);
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++)
if(vis3[i][j] == 0 && g[i][j] == 0 && ((i + j )% 2 == T))
{
if(g[i + 1][j] == 0 && i + 1 <= n)
{
G[vis2[i][j]].push_back(vis2[i + 1][j]);
vis3[i + 1][j] = 1;
}
if(g[i - 1][j] == 0 && i - 1 >= 1)
{
G[vis2[i][j]].push_back(vis2[i - 1][j]);
vis3[i - 1][j] = 1;
}
if(g[i][j + 1] == 0 && j + 1 <= m)
{
G[vis2[i][j]].push_back(vis2[i][j + 1]);
vis3[i][j + 1] = 1;
}
if(g[i][j - 1] == 0 && j - 1 >= 1)
{
G[vis2[i][j]].push_back(vis2[i][j - 1]);
vis3[i][j - 1] = 1;
}
}
int t = solve();
//cout << t << endl;
if(2 * t == (n * m - h) && (n * m - h) % 2 == 0 && cnt1 == cnt2)
flag = 1;
for(int i = 1; i <= sum; i++)
{
G[i].clear();
}
}
if(flag)cout << "YES" << endl;
else cout << "NO" << endl;
}
return 0;
}