import std.algorithm;
import std.conv;
import std.range;
import std.stdio;
import std.string;
import std.typecons;

void main()
{
	stdin.byLineCopy.parse.expand.solve.writeln;
}

auto parse( Range )( Range input )
if( isInputRange!Range && is( ElementType!Range == string ) )
{
	auto n = input.front.strip.to!( long );
	
	auto rs = new long[ 2 ][ n ];
	foreach( ref r; rs )
	{
		input.popFront;
		r = input.front.split.to!( long[] );
	}
	
	auto bs = new long[ 2 ][ n ];
	foreach( ref b; bs )
	{
		input.popFront;
		b = input.front.split.to!( long[] );
	}
	
	return tuple( n, rs, bs );
}

auto solve( long n, long[ 2 ][] rs, long[ 2 ][] bs )
{
	rs.sort();
	bs.sort();
	
	auto rbtable = new bool[][]( n, n );
	foreach( x, r; rs )
	{
		foreach( y, b; bs )
		{
			if( r[ 0 ] < b[ 0 ] && r[ 1 ] < b[ 1 ] ) rbtable[ y ][ x ] = true;
		}
	}
	rbtable = rbtable.sort!( ( a, b ) => a.count( true ) < b.count( true ) ).array;
	
	return solve2( rbtable );
}

long solve2( bool[][] rbtable )
{
	while( 0 < rbtable.length && rbtable[ 0 ].count( true ) <= 0 )
	{
		rbtable = rbtable[ 1 .. $ ];
	}
	
	if( rbtable.length <= 0 ) return 0;
	
	auto cm = 0L;
	
	foreach( x, u; rbtable[ 0 ] )
	{
		if( u )
		{
			auto rbtable2 = rbtable[ 1 .. $ ].dup;
			foreach( ref btable2; rbtable2 )
			{
				btable2[ x ] = false;
			}
			auto c = 1 + solve2( rbtable2 );
			if( cm < c ) cm = c;
		}
	}
	
	return cm;
}
