Time Limit: 2000MS | Memory Limit: 65536K | |
Total Submissions: 14479 | Accepted: 4501 |
Description
Input
Output
Sample Input
4 3 2 2 1 3 3
Sample Output
YES
Hint
题意:给出一个矩形N*M棋盘,有K个格子是空洞,然后用2*1的矩形,对所有非空洞的格子进行覆盖,问能否完全覆盖。
分析:二分图匹配问题。关键问题是如何建图,我们可以把每两个相邻的非空格子用一条边连接起来,这样的话相当于这两个格子处于分别处于两个集合当中,这样的话两个相邻的格子就不会处于同一个集合当中。然后这样子连边就构成了一个二分图了。然后求出最大匹配数。如果匹配数 + k = N*M,输出“YES”。
题目链接:http://poj.org/problem?id=2446
代码清单:
#include<map> #include<queue> #include<cmath> #include<stack> #include<ctime> #include<cctype> #include<string> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; typedef long long ll; const int maxn = 32 + 5; const int maxv = 2000 + 5; int m,n,k; int x,y,cnt; int match[maxv]; bool vis[maxv]; int num[maxn][maxn]; bool hole[maxn][maxn]; bool graph[maxv][maxv]; bool dfs(int u){ //匈牙利算法 for(int v=1;v<=cnt;v++){ if(!vis[v]&&graph[u][v]){ vis[v]=true; if(match[v]==-1 || dfs(match[v])){ match[v]=u; return true; } } }return false; } bool ok(){ int ans=0; for(int i=1;i<=cnt;i++){ memset(vis,false,sizeof(vis)); if(dfs(i)) ans++; } if(ans==cnt) return true; return false; } int main(){ scanf("%d%d%d",&m,&n,&k); memset(match,-1,sizeof(match)); memset(hole,false,sizeof(hole)); memset(graph,false,sizeof(graph)); for(int i=0;i<k;i++){ scanf("%d%d",&x,&y); hole[y-1][x-1]=true; } if((n*m-k)&1) printf("NO\n"); //奇偶性剪枝 else{ cnt=0; for(int i=0;i<m;i++){ for(int j=0;j<n;j++){ if(!hole[i][j]) num[i][j]=++cnt; } } //建立二分图 for(int i=0;i<m;i++){ for(int j=0;j<n;j++){ if(!hole[i][j]){ if(i-1>=0&&!hole[i-1][j]) graph[num[i][j]][num[i-1][j]]=true; if(i+1<m&&!hole[i+1][j]) graph[num[i][j]][num[i+1][j]]=true; if(j-1>=0&&!hole[i][j-1]) graph[num[i][j]][num[i][j-1]]=true; if(j+1<n&&!hole[i][j+1]) graph[num[i][j]][num[i][j+1]]=true; } } } if(ok()) printf("YES\n"); else printf("NO\n"); } return 0; }