/* 匈牙利算法 二分匹配 最小点覆盖=最大匹配。 即踢掉最小点覆盖 */ #include<stdio.h> #include<string.h> #include<stdlib.h> #include<algorithm> #include<iostream> #include<queue> #include<map> #include<math.h> using namespace std; typedef long long ll; //typedef __int64 int64; const int maxn = 1015; const int inf = 0x7fffffff; const double pi=acos(-1.0); const double eps = 1e-8; struct Edge{ int v,next; }edge[ maxn<<4 ]; struct Node{ int x,y; }sum[ maxn<<1 ]; int cnt,head[ maxn<<1 ]; int vis[ maxn<<1 ],mylink[ maxn<<1 ]; void init(){ cnt = 0; memset( head,-1,sizeof( head ) ); } void addedge( int a,int b ){ edge[ cnt ].v = b; edge[ cnt ].next = head[ a ]; head[ a ] = cnt++; } bool km( int u ){ for( int i=head[ u ];i!=-1;i=edge[ i ].next ){ int v = edge[ i ].v; if( vis[ v ]==0 ){ vis[ v ] = 1; if( mylink[ v ]==-1||km( mylink[v] ) ){ mylink[ v ] = u; return true; } } } return false; } int solve( int n,int m ){ memset( mylink,-1,sizeof( mylink ) ); int ans = 0; for( int i=1;i<=n;i++ ){ memset( vis,0,sizeof( vis ) ); if( km(i) ) ans++; } return ans; } bool Judge( int i,int j ){ int x1 = sum[i].x; int y1 = sum[i].y; int x2 = sum[j].x; int y2 = sum[j].y; if( x1==x2 ){ if( y1==y2 ) return true; if( y1==y2+1 ) return true; } if( x1+1==x2 ){ if( y1==y2 ) return true; if( y1==y2+1 ) return true; } return false; } int main(){ int n,m; while( scanf("%d%d",&n,&m)==2,n+m ){ init(); int cc = 1; for( int i=1;i<=n;i++ ) scanf("%d%d",&sum[cc].x,&sum[cc].y),cc++; for( int j=1;j<=m;j++ ) scanf("%d%d",&sum[cc].x,&sum[cc].y),cc++; for( int i=1;i<=n;i++ ){ for( int j=n+1;j<cc;j++ ){ if( Judge( i,j ) ){ addedge( i,j ); } } } printf("%d ",cc-1-solve( n,m )); } return 0; }