题目大意:
n*m的网格,其中有k个格子为漏洞,不能放东西。问你用1*2的格子能不能把网格放慢。
题解:
二分图匹配问题
需要自己建立二分图。位于(i,j)的格子,可以与上,下,左,右的格子连边。如果(i+j)为偶数,那么他连向的格子的(i1+J1)一定为奇数。根据i+j的奇偶性可以把格子分成两个集合,而且为每个集合中的格子不会相连,这样就形成了一个二分图。然后用匈牙利算法求解即可。
如果,最大配对的结果*2+k==n*m那么答案为YES。否则为NO
#include<iostream> #include<cstdio> #include<cstring> using namespace std; bool a[1001][1001]; bool e[1001][1001]; bool v[1001]; int result[1001]; int num[1001][1001]; int n,m,k,n1,n2; bool find(int x) { for(int i=1;i<=n2;i++) if(a[x][i]==1 && !v[i]) { v[i]=true; if(result[i]==0 || find(result[i])) { result[i]=x; return true; } } return false; } void build(int x0,int y0,int &n1,int x1,int y1,int &n2) { if(x1<1||y1<1||x1>m||y1>n)return; if(!e[x1][y1])return; int l1,l2; if(num[x0][y0]!=0)l1=num[x0][y0];else { n1++; num[x0][y0]=n1; l1=n1; } if(num[x1][y1]!=0)l2=num[x1][y1];else { n2++; num[x1][y1]=n2; l2=n2; } a[l1][l2]=true; } int main() { while(scanf("%d%d%d",&m,&n,&k)!=EOF) { memset(a,false,sizeof(a)); memset(v,false,sizeof(v)); memset(e,true,sizeof(e)); memset(num,0,sizeof(num)); memset(result,0,sizeof(result)); for(int i=1;i<=k;i++) { int x,y; scanf("%d%d",&y,&x); e[x][y]=false; } n1=0,n2=0; for(int i=1;i<=m;i++) for(int j=1;j<=n;j++) if(e[i][j] && (i+j)%2==0) { build(i,j,n1,i+1,j,n2); build(i,j,n1,i-1,j,n2); build(i,j,n1,i,j+1,n2); build(i,j,n1,i,j-1,n2); } int ans=0; for(int i=1;i<=n1;i++) { memset(v,0,sizeof(v)); if(find(i))ans++; } if(ans*2+k==n*m)printf("YES\n");else printf("NO\n"); } return 0; }