题目大意:
给定一个M*N大小的棋盘,其中的一些点是洞,无法放置卡片,卡片是占两个格子的矩形方块。现在用程序来判断 是否可以用卡片不重叠的 将整个棋盘填满?
思路:
看到这道题,压根刚开始没想起来用二分图,最大匹配来做。后来看了网上的博客,才有些思路。 首先要明确的是,在棋盘中,[i,j]表示的点如果i+j为偶数,那么周围的四个点的横纵坐标之和一定为奇数,反过来也一样。那么我们就可以将 奇数表示的点 放在一个集合里,偶数表示的点 放在另一个集合里。 最后,求这个图的最大匹配。
如果ans * 2 等于格子数减去洞的数量,那么就输出 YES,否则输出NO。 因为每条边 占 两格,所以ans 要乘以2
本题的关键还是建图,的确刚开始比较难想到。还有比较关键的是,如果从偶数的集合里面开始寻找增广路的话,那么在map数组赋值为1 时,要使每个偶数点指向奇数点,也就是说,不仅要 path[i][j]不等于1,而且(i+j)%2 == 1,这里是一个注意点 ; 当然你从奇数的集合里面开始的话,使每个奇数点指向偶数点 也是可以的。
#include <iostream>
using namespace std;
#define MAX 35
int map[MAX*MAX][MAX*MAX];
bool visit[MAX*MAX];
int check[MAX*MAX];
int m,n,k,temp1,temp2;
bool dfs(int v){
for(int i=1;i<temp2;i++){
if(!visit[i]&&map[v][i]){
visit[i] = 1;
if(check[i] == -1 || dfs(check[i])){
check[i] = v;
return true;
}
}
}
return false;
}
void hungry(){
int ans = 0;
memset(check,-1,sizeof(check));
for(int i=1;i<temp1;i++){
memset(visit,0,sizeof(visit));
if(dfs(i))
ans++;
}
if((ans*2)==(m*n-k))
cout<<"YES"<<endl;
else
cout<<"NO"<<endl;
}
int main(){
int i,j,a,b;
scanf("%d %d %d",&m,&n,&k);
int path[MAX][MAX];
memset(path,0,sizeof(path));
for(i=0;i<k;i++){
scanf("%d %d",&a,&b);
path[b][a] = -1;
}
temp1 = 1;
temp2 = 1;
for(i=1;i<=m;i++){
for(j=1;j<=n;j++){
if(path[i][j]==0){
if((i+j)%2==0)
path[i][j] = temp1++;
else
path[i][j] = temp2++;
}
}
}
memset(map,0,sizeof(map));
for(i=1;i<=m;i++){
for(j=1;j<=n;j++){
if(path[i][j]!=-1 && (i+j)%2 == 1){
if(path[i-1][j]>=1)
map[path[i-1][j]][path[i][j]] = 1;
if(path[i+1][j]>=1)
map[path[i+1][j]][path[i][j]] = 1;
if(path[i][j-1]>=1)
map[path[i][j-1]][path[i][j]] = 1;
if(path[i][j+1]>=1)
map[path[i][j+1]][path[i][j]] = 1;
}
}
}
hungry();
return 0;
}