Problem:
マトリョーシカ

マトリョーシカとは女性像をかたどった木製の人形で、ロシアの代表的な民芸品です。マトリョーシカは、大きな人形の中にそれより小さな人形が入っている入れ子構造になっており、大きさの異なる複数の人形で構成されています。このような入れ子構造にするため、各人形の胴体は上下で分割できる筒状の構造になっています。マトリョーシカは職人の手で手作りされるため、一つ一つの人形は世界に一つしかない非常に貴重なものになります。

兄弟である一郎君と次郎君は、マトリョーシカで遊ぶのが大好きで、各自がそれぞれ1組のマトリョーシカを持っていました。一郎君のマトリョーシカは n 個の人形から構成されており、次郎君のマトリョーシカは m 個の人形から構成されています。

ある日、好奇心が旺盛な一郎君は、これら2組のマトリョーシカに含まれる人形たちを組み合わせて、より多くの人形を含む新たなマトリョーシカを作れないかと考えました。つまり、n + m 個の人形を使い、k 個の人形からなる１組のマトリョーシカを作ることを試みたのです。n と m の大きい方よりも k を大きくすることができれば、一郎君の目的は達成されます。

兄弟は2人仲良く、どのように人形を組み合わせれば k の値を最大にできるかを考えました。しかし、幼い2人にとってこの問題はあまりにも難しいので、年上のあなたはプログラムを作成して弟たちを助けることにしました。

一郎君と次郎君のマトリョーシカの人形の情報を入力とし、新たなマトリョーシカが含む人形の数 k を出力するプログラムを作成して下さい。入力される人形に大きさが同じものは存在しません。また、人形を高さ h 半径 r の円柱とみなした場合、高さh、半径 r の人形が含むことのできる人形は x < h かつ y < r を満たす高さ x 半径 y の人形です。

Input

複数のデータセットの並びが入力として与えられます。入力の終わりはゼロひとつの行で示されます。各データセットは以下の形式で与えられます。

n
h1 r1
h2 r2
:
hn rn
m
h1 r1
h2 r2
:
hm rm

１行目に一郎君のマトリョーシカの人形の数 n (n ≤ 100)、続く n 行に一郎君の第 i の人形の高さ hi と半径 ri (hi, ri < 1000) が与えられます。

続く行に二郎君のマトリョーシカの人形の数 m (m ≤ 100)、続く m 行に二郎君の第 i の人形の高さ hi と半径 ri (hi, ri < 1000) が与えられます。

データセットの数は 20 を越えない。

Output

入力データセットごとに新たなマトリョーシカが含む人形の数 k を出力します。

Sample Input

6
1 1
4 3
6 5
8 6
10 10
14 14
5
2 2
5 4
6 6
9 8
15 10
4
1 1
4 3
6 5
8 6
3
2 2
5 4
6 6
4
1 1
4 3
6 5
8 6
4
10 10
12 11
18 15
24 20
0

Output for the Sample Input

9
6
8

Solution in C# (judge verdict: Accepted)

using System;

class Program
{ 
	public static int Main()
	{
		Scanner cin = new Scanner();
		while (true)
		{
			int n = cin.nextInt();
			if (n == 0)
			{
				break;
			}
			bool[,] hasdoll = new bool[1000, 1000];
			for (int i = 0; i < n; i++)
			{
				hasdoll[cin.nextInt(), cin.nextInt()] = true;
			}
			int m = cin.nextInt();
			for (int i = 0; i < m; i++)
			{
				hasdoll[cin.nextInt(), cin.nextInt()] = true;
			}
			int[,] dp = new int[1000, 1000];
			for (int i = 0; i < 1000; i++)
			{
				for (int j = 0; j < 1000; j++)
				{
					if (hasdoll[i, j])
					{
						if (i > 0 && j > 0)
						{
							dp[i, j] = dp[i - 1, j - 1] + 1;
						}
						if (i > 0)
						{
							dp[i, j] = Math.Max(dp[i, j], hasdoll[i - 1, j] ? dp[i - 1, j] : dp[i - 1, j] + 1);
						}
						if (j > 0)
						{
							dp[i, j] = Math.Max(dp[i, j], hasdoll[i, j - 1] ? dp[i, j - 1] : dp[i, j - 1] + 1);
						}
						if (i == 0 && j == 0)
						{
							dp[i, j] = 1;
						}
					}
					else
					{
						if (i > 0 && j > 0)
						{
							dp[i, j] = dp[i - 1, j - 1];
						}
						if (i > 0)
						{
							dp[i, j] = Math.Max(dp[i, j], hasdoll[i - 1, j] ? dp[i - 1, j] - 1: dp[i - 1, j]);
						}
						if (j > 0)
						{
							dp[i, j] = Math.Max(dp[i, j], hasdoll[i, j - 1] ? dp[i, j - 1] - 1: dp[i, j - 1]);
						}
						if (i == 0 && j == 0)
						{
							dp[i, j] = 0;
						}
					}
				}
			}
			Console.WriteLine(dp[999, 999]);
		}
		return 0;
	}

}

class Scanner {
	string[] s;
	int i;

	char[] cs = new char[] { ' ' };

	public Scanner() {
		s = new string[0];
		i = 0;
	}

	public string next() {
		if (i < s.Length) return s[i++];
		do {
			s = Console.ReadLine().Split(cs, StringSplitOptions.RemoveEmptyEntries);
		} while ((s.Length == 1 && s[0] == "") || s.Length == 0);
		i = 0;
		return s[i++];
	}

	public int nextInt() {
		return int.Parse(next());
	}

	public long nextLong() {
		return long.Parse(next());
	}

	public double nextDouble() {
		return double.Parse(next());
	}

}