codevs 3052 多米诺(二分图匹配)
3052 多米诺
时间限制: 1 s
空间限制: 256000 KB
题目等级 : 钻石 Diamond
题目描述 Description
一个矩形可以划分成M*N个小正方形,其中有一些小正方形不能使用。一个多米诺骨牌占用两个相邻的小正方形。试问整个区域内最多可以不重叠地放多少个多米诺骨牌且不占用任何一个被标记为无法使用的小正方形。
输入描述 Input Description
第一行有两个用空格隔开的正整数M和N。
第二行有一个正整数K,表示共有K个小正方形不能使用。输入数据保证K<=M*N。
以下K行每行有两个用空格隔开的数X和Y,表示第X行的第Y个小正方形不能使用。
输出描述 Output Description
输出最多能放多少个多米诺骨牌。
样例输入 Sample Input
3 3
2
1 1
2 2
样例输出 Sample Output
3
数据范围及提示 Data Size & Hint
对于30%的数据,M=1;
对于50%的数据,M<=2;
对于70%的数据,M<=3;
对于100%的数据,M<=50,N<=50。
/* 二分图匹配 把每个点向上下左右四个方向连一条边 染色后求最大匹配 写的不是很好...... */ #include<iostream> #include<cstdio> #include<cstring> using namespace std; int n,m,t,topt,ans; int first[4000],Color[4000],match[4000]; bool a[60][60],f[4000]; int b[5]={0,0,1,0,-1}; int c[5]={0,1,0,-1,0}; struct edge { int to; int next; }e[10010]; void add(int x,int y) { topt++; e[topt].to=y; e[topt].next=first[x]; first[x]=topt; } void dfs(int x,int p) { int t; if(p==1)t=2; else t=1; if(Color[x])return; Color[x]=p; for(int i=first[x];i;i=e[i].next) { int to=e[i].to; dfs(to,t); } } int DFS(int x) { for(int i=first[x];i;i=e[i].next) { int to=e[i].to; if(!f[to]) { f[to]=1; if(!match[to]||DFS(match[to])) { match[to]=x; return 1; } } } return 0; } int main() { scanf("%d%d",&n,&m); scanf("%d",&t); while(t--) { int x,y; scanf("%d%d",&x,&y); a[x][y]=1; } for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) { if(a[i][j])continue; for(int k=1;k<=4;k++) { int x=i+b[k]; int y=j+c[k]; if(x>=1&&x<=n&&y>=1&&y<=m&&!a[x][y]) add((i-1)*m+j,(x-1)*m+y); } } } for(int i=1;i<=n*m;i++) if(!Color[i])dfs(i,1); for(int i=1;i<=n*m;i++) if(Color[i]==1) { memset(f,0,sizeof(f)); ans+=DFS(i); } printf("%d\n",ans); return 0; }