题意:给出一个m*n的矩阵,其中有的地方有坑,然后用1*2的纸片去覆盖图,纸片不能重复,能够把出了坑的地方其他全部覆盖的话输出YES,否则NO。
分析:按其奇偶性建图的,因为要用1*2的纸片覆盖,那么两个值(i+j)必然一个奇数一个偶数,然后分别给图中的奇数偶数点依次从1开始标号,相邻的按其标号建图,匈牙利。因为必然是一个奇数点对应一个相邻偶数点,那么只要求任意奇数或偶数的最大匹配就可以了。
总结:二分图的第一道题,了解了匈牙利算法,对dfs实现匈牙利算法还不熟悉(不能熟练写出递归程序,长期以来的问题)。
代码:
#include<iostream> #include<cstdio> #include<cstring> using namespace std; #define Del(x,y) memset(x,y,sizeof(x)) int path[33][33],map[600][600],vis[600],link[600]; int cnt1,cnt2,m,n,k; int dfs(int x) { for(int i=1; i<=cnt2; i++) if(map[x][i]==1) if(vis[i]==0) { vis[i]=1; if(link[i]==-1||dfs(link[i])) { link[i]=x; return 1; } } return 0; } void solve() { int ans=0; Del(link,-1); for(int i=1; i<=cnt1; i++) { Del(vis,0); if(dfs(i)) ans++; } //printf("%d ",ans); if((ans*2)==(n*m-k)) printf("YES "); else printf("NO "); } int main() { int x,y; scanf("%d%d%d",&m,&n,&k); Del(path,0); for(int i=0;i<k;i++) { scanf("%d%d",&x,&y); path[y][x]=-1; } cnt1=1,cnt2=1; for(int i=1; i<=m; i++) for(int j=1; j<=n; j++) { if(path[i][j]==0) { if((i+j)%2==1) path[i][j]=cnt1++; else path[i][j]=cnt2++; } } cnt1--;cnt2--; Del(map,0); for(int i=1; i<=m; i++) for(int j=1; j<=n; j++) if(path[i][j]!=-1&&(i+j)%2==1) { if(path[i-1][j]>0) map[path[i-1][j]][path[i][j]]=1; if(path[i+1][j]>0) map[path[i+1][j]][path[i][j]]=1; if(path[i][j-1]>0) map[path[i][j-1]][path[i][j]]=1; if(path[i][j+1]>0) map[path[i][j+1]][path[i][j]]=1; } solve(); return 0; }