题目大意:
给定一个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; }