Problem:
星座探し

問題

あなたは星空の写真の中から星座を探している．写真には必ず，探したい星座と同じ形・向き・大きさの図形がちょうど一つ含まれている．ただし，写真の中には星座を構成する星以外に余分な星が写っている可能性がある．

例えば，図 1 の星座は図 2 の写真に含まれている（丸で囲んで示した）．与えられた星座の星の座標を x 方向に 2， y 方向に −3 だけ平行移動すると写真の中の位置になる．

探したい星座の形と写真に写っている星の位置が与えられたとき，星座の座標を写真の中の座標に変換するために平行移動するべき量を答えるプログラムを書け．

図 1: 探したい星座

図 2: 星空の写真

入力

入力は複数のデータセットからなる．各データセットは以下の形式で与えられる．

入力の 1 行目には探したい星座を構成する星の個数 m が書かれている．続く m 行には探したい星座を構成する m 個の星の x 座標と y 座標を示す整数が空白区切りで書かれている． m+2 行目には写真に写っている星の個数 n が書かれている．続く n 行には写真に写っている n 個の星の x 座標と y 座標を示す整数が空白区切りで書かれている．

星座を構成する m 個の星の位置はすべて異なる．また，写真に写っている n 個の星の位置はすべて異なる． 1 ≤ m ≤ 200， 1 ≤ n ≤ 1000 である．星の x 座標と y 座標はすべて 0 以上 1000000 以下である．

m が 0　のとき入力の終わりを示す. データセットの数は 5 を超えない．

出力

各データセットの出力は 1 行からなり， 2 個の整数を空白区切りで書く．これらは探したい星座の座標をどれだけ平行移動すれば写真の中の座標になるかを表す．最初の整数が x 方向に平行移動する量，次の整数が y 方向に平行移動する量である．

入出力例

入力例

5
8 5
6 4
4 3
7 10
0 10
10
10 5
2 7
9 7
8 10
10 2
1 2
8 1
6 7
6 0
0 9
5
904207 809784
845370 244806
499091 59863
638406 182509
435076 362268
10
757559 866424
114810 239537
519926 989458
461089 424480
674361 448440
81851 150384
459107 795405
299682 6700
254125 362183
50795 541942
0

出力例

2 -3
-384281 179674

入出力例の１つ目は上の図に対応している．

上記問題文と自動審判に使われるデータは、情報オリンピック日本委員会が作成し公開している問題文と採点用テストデータです。

Solution in C# (judge verdict: Accepted)

using System;
using System.Collections.Generic;
using System.Linq;

namespace _524_SearchingConstellation
{
	class Program
	{
		static void Main ( string[] args )
		{
			while (true)
			{
				//input
				int constellationElementCount = int.Parse (Console.ReadLine ());

				if (constellationElementCount == 0)
				{
					break;
				}

				Point[] constellationElementPoint = new Point[constellationElementCount];

				for (int lp = 0; lp < constellationElementPoint.Length; lp++)
				{
					int[] items = Console.ReadLine ().Split (' ').Select (str => int.Parse (str)).ToArray ();
					constellationElementPoint[lp] = new Point (items[0], items[1]);
				}

				int starCount = int.Parse (Console.ReadLine ());

				Point[] starPoint = new Point[starCount];
				for (int lp = 0; lp < starPoint.Length; lp++)
				{
					int[] items = Console.ReadLine ().Split (' ').Select (str => int.Parse (str)).ToArray ();
					starPoint[lp] = new Point (items[0], items[1]);
				}

				//process
				IEnumerable<Point> constellationList = constellationElementPoint.OrderBy (item => item.X).ThenBy (item => item.Y);
				List<Point> starList = starPoint.OrderBy (item => item.X).ThenBy (item => item.Y).ToList ();
				IComparer<Point> compare = new PointCompare ();

				Point movePoint = null;

				//?§?????????????????????????????????????
				foreach (var item in starList)
				{
					//?§?????????????????±???????
					int x = item.X - constellationList.First ().X;
					int y = item.Y - constellationList.First ().Y;
					movePoint = new Point (x, y);

					//?§???????????????§?????????
					bool isMatch = true;

					foreach (var item2 in constellationList)
					{
						int x2 = item2.X + movePoint.X;
						int y2 = item2.Y + movePoint.Y;

						//?????????????§?????????????
						Point destinationPoint = new Point (x2, y2);
						int result = starList.BinarySearch (destinationPoint, compare);

						//?§???????????????????????????°
						if (result < 0)
						{
							isMatch = false;
							break;
						}
					}

					//?????´?????????????????????????????°
					if (isMatch)
					{
						break;
					}
				}

				//output
				Console.WriteLine (movePoint.X + " " + movePoint.Y);
			}
		}
	}

	class Point
	{
		public Point ( int x, int y )
		{
			this.X = x;
			this.Y = y;
		}

		public int X { private set; get; }
		public int Y { private set; get; }
	}

	class PointCompare : IComparer<Point>
	{
		public int Compare ( Point ob1, Point ob2 )
		{
			if (ob1.X < ob2.X)
			{
				return -1;
			}
			else if (ob1.X > ob2.X)
			{
				return 1;
			}
			else
			{
				if (ob1.Y < ob2.Y)
				{
					return -1;
				}
				else if (ob1.Y > ob2.Y)
				{
					return 1;
				}
				else
				{
					return 0;
				}
			}
		}
	}
}