Problem:
Problem D:
Rotation Estimation
Mr. Nod is an astrologist and has defined a new constellation. He took two photos of the
constellation to foretell a future of his friend. The constellation consists of
n
stars. The shape
of the constellation in these photos are the same, but the angle of them are different because
these photos were taken on a different day. He foretells a future by the difference of the angle
of them.
Your job is to write a program to calculate the difference of the angle of two constellation.
Input
The input is a sequence of datasets. Each dataset is given in the following format:
n
x
1,1
y
1,1
...
x
1,
n
y
1,
n
x
2,1
y
2,1
...
x
2,
n
y
2,
n
The first line of each dataset contains a positive integers
n
(
n
≤ 1,000). The next
n
lines contain
two real numbers
x
1,
i
and
y
1,
i
(|
x
1,
i
|, |
y
1,
i
| ≤ 100), where (
x
1,
i
,
y
1,
i
) denotes the coordinates of
the
i
-th star of the constellation in the first photo. The next
n
lines contain two real numbers
x
2,
i
and
y
2,
i
(|
x
2,
i
|, |
y
2,
i
| ≤ 100), where (
x
2,
i
,
y
2,
i
) denotes the coordinates of the
i
-th star of the
constellation in the second photo.
Note that the ordering of the stars does
not
matter for the sameness. It is guaranteed that
distance between every pair of stars in each photo is larger than 10
-5
.
The input is terminated in case of
n
= 0. This is not part of any datasets and thus should not
be processed.
Output
For each dataset, you should print a non-negative real number which is the difference of the
angle of the constellation in the first photo and in the second photo. The difference should be in radian, and should not be negative. If there are two or more solutions, you should print
the smallest one. The difference may be printed with any number of digits after decimal point,
provided the absolute error does not exceed 10
-7
. No extra space or character is allowed.
Sample Input
3
0.0 0.0
1.0 1.0
0.0 1.0
3.0 3.0
2.0 2.0
3.0 2.0
0
Output for the Sample Input
3.14159265359

Submitted solutions:

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 4000000000000000000 //オーバーフローに注意
#define MOD 1000000007
//#define EPS 0.000000001
using namespace std;


#define EPS 0.000000001
#define SIZE 1005

struct Point{
	Point(double arg_x,double arg_y){
		x = arg_x;
		y = arg_y;
	}

	Point(){
		x = y = 0.0;
	}

	Point operator + (Point p){ return Point(x+p.x,y+p.y); }
	Point operator - (Point p){ return Point(x-p.x,y-p.y);}
	Point operator * (double a){ return Point(a*x,a*y); }
	Point operator / (double a){ return Point(x/a,y/a); }

	double abs(){ return sqrt(norm()); }
	double norm(){ return x*x + y*y; }

	bool operator<(const Point &p) const{

		if(fabs(x-p.x) > EPS){

			return x < p.x;
		}else{

			return y < p.y;
		}
	}

	bool operator == (const Point &p) const{
		return fabs(x-p.x) < EPS && fabs(y-p.y) < EPS;
	}


	void debug(){

		printf("(%.3lf,%.3lf)\n",x,y);
	}

	double x,y;
};

typedef Point Vector;
typedef vector<Point> Polygon;

int N;
Point A[SIZE],B[SIZE],work[SIZE];

double norm(Vector a){
	return a.x*a.x+a.y*a.y;
}

double abs(Vector a){
	return sqrt(norm(a));
}

double cross(Vector a,Vector b){
    return a.x*b.y-a.y*b.x;
}

double dot(Vector a,Vector b){
    return a.x*b.x + a.y*b.y;
}

static const int COUNTER_CLOCKWISE = 1;
static const int CLOCKWISE = -1;
static const int ONLINE_BACK = 2;
static const int ONLINE_FRONT = -2;
static const int ON_SEGMENT = 0;

/*
 * p0を基準点として、p1から見てp2が
 * 反時計回り側にあれば
 * COUNTER_CLOCKWISE
 * */
int ccw(Point p0,Point p1,Point p2){

	Vector a = p1 - p0;
	Vector b = p2 - p0;

	if(cross(a,b) > EPS)return COUNTER_CLOCKWISE;
	if(cross(a,b) < -EPS)return CLOCKWISE;
	if(dot(a,b) < -EPS)return ONLINE_BACK;
	if(a.norm() < b.norm())return ONLINE_FRONT;

	return ON_SEGMENT;
}

/*点moveをbaseを中心にradラジアン回転させる
rad > 0なら反時計回り、rad < 0なら時計周り
*/
Point rotate(Point base,Point move,double rad){

	Point ret;
	move = move-base;

	ret.x = move.x*cos(rad)-move.y*sin(rad);
	ret.y = move.x*sin(rad)+move.y*cos(rad);

	ret = ret+base;

	return ret;
}

//点のradを求める関数
double calc_rad(Point p){

	if(p.y == 0){

		if(p.x > 0){

			return 0;

		}else{ //p.x < 0

			return M_PI;
		}

	}else if(p.x == 0){

		if(p.y > 0){

			return M_PI/2.0;
		}else{


			return 3*M_PI/2.0;
		}

	}else{

		double base = atan(fabs(p.y)/fabs(p.x));

		if(p.x > 0){

			if(p.y > 0){

				return base;

			}else{ //p.y < 0

				return 2*M_PI-base;
			}

		}else{ //p.x < 0

			if(p.y > 0){

				return M_PI-base;

			}else{

				return base+M_PI;
			}
		}
	}
}


void func(){

	Point mid_A = Point(0,0);

	for(int i = 0; i < N; i++){

		scanf("%lf %lf",&A[i].x,&A[i].y);
		mid_A = mid_A + A[i];
	}
	mid_A = mid_A/N;

	for(int i = 0; i < N; i++){

		A[i] = A[i]-mid_A;
	}
	sort(A,A+N);

	Point mid_B = Point(0,0);
	for(int i = 0; i < N; i++){

		scanf("%lf %lf",&B[i].x,&B[i].y);
		mid_B = mid_B + B[i];
	}

	mid_B = mid_B/N;
	for(int i = 0; i < N; i++){

		B[i] = B[i]-mid_B;
	}

	double ans = BIG_NUM;

	double base_rad = calc_rad(A[0]);

	for(int i = 0; i < N; i++){

		double tmp_rad = calc_rad(B[i]);
		for(int k = 0; k < N; k++){

			work[k] = rotate(Point(0,0),B[k],base_rad-tmp_rad);
		}
		sort(work,work+N);

		bool FLG = true;
		for(int k = 0; k < N; k++){
			if(A[k] == work[k]){

				//Do nothing

			}else{

				FLG = false;
				break;
			}
		}

		if(!FLG)continue;

		double diff = base_rad-tmp_rad;
		if(diff < 0){

			diff += 2*M_PI;
		}

		if(diff > M_PI){

			diff = 2*M_PI-diff;
		}

		ans = min(ans,diff);
	}

	printf("%.12lf\n",ans);
}

int main(){

	while(true){

		scanf("%d",&N);
		if(N == 0)break;

		func();
	}

	return 0;
}
accuracy: 1
time_ms: 120
memory_kb: 3800
final_rank: 18

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 4000000000000000000 //オーバーフローに注意
#define MOD 1000000007
//#define EPS 0.000000001
using namespace std;


#define EPS 0.000000001
#define SIZE 1005

struct Point{
	Point(double arg_x,double arg_y){
		x = arg_x;
		y = arg_y;
	}

	Point(){
		x = y = 0.0;
	}

	Point operator + (Point p){ return Point(x+p.x,y+p.y); }
	Point operator - (Point p){ return Point(x-p.x,y-p.y);}
	Point operator * (double a){ return Point(a*x,a*y); }
	Point operator / (double a){ return Point(x/a,y/a); }

	double abs(){ return sqrt(norm()); }
	double norm(){ return x*x + y*y; }

	bool operator<(const Point &p) const{

		if(fabs(x-p.x) > EPS){

			return x < p.x;
		}else{

			return y < p.y;
		}
	}

	bool operator == (const Point &p) const{
		return fabs(x-p.x) < EPS && fabs(y-p.y) < EPS;
	}


	void debug(){

		printf("(%.3lf,%.3lf)\n",x,y);
	}

	double x,y;
};

typedef Point Vector;
typedef vector<Point> Polygon;

int N;
Point A[SIZE],B[SIZE],work[SIZE];

double norm(Vector a){
	return a.x*a.x+a.y*a.y;
}

double abs(Vector a){
	return sqrt(norm(a));
}

double cross(Vector a,Vector b){
    return a.x*b.y-a.y*b.x;
}

double dot(Vector a,Vector b){
    return a.x*b.x + a.y*b.y;
}

static const int COUNTER_CLOCKWISE = 1;
static const int CLOCKWISE = -1;
static const int ONLINE_BACK = 2;
static const int ONLINE_FRONT = -2;
static const int ON_SEGMENT = 0;

/*
 * p0を基準点として、p1から見てp2が
 * 反時計回り側にあれば
 * COUNTER_CLOCKWISE
 * */
int ccw(Point p0,Point p1,Point p2){

	Vector a = p1 - p0;
	Vector b = p2 - p0;

	if(cross(a,b) > EPS)return COUNTER_CLOCKWISE;
	if(cross(a,b) < -EPS)return CLOCKWISE;
	if(dot(a,b) < -EPS)return ONLINE_BACK;
	if(a.norm() < b.norm())return ONLINE_FRONT;

	return ON_SEGMENT;
}

/*点moveをbaseを中心にradラジアン回転させる
rad > 0なら反時計回り、rad < 0なら時計周り
*/
Point rotate(Point base,Point move,double rad){

	Point ret;
	move = move-base;

	ret.x = move.x*cos(rad)-move.y*sin(rad);
	ret.y = move.x*sin(rad)+move.y*cos(rad);

	ret = ret+base;

	return ret;
}

//点のradを求める関数
double calc_rad(Point p){

	if(p.y == 0){

		if(p.x > 0){

			return 0;

		}else{ //p.x < 0

			return M_PI;
		}

	}else if(p.x == 0){

		if(p.y > 0){

			return M_PI/2.0;
		}else{


			return 3*M_PI/2.0;
		}

	}else{

		double base = atan(fabs(p.y)/fabs(p.x));

		if(p.x > 0){

			if(p.y > 0){

				return base;

			}else{ //p.y < 0

				return 2*M_PI-base;
			}

		}else{ //p.x < 0

			if(p.y > 0){

				return M_PI-base;

			}else{

				return base+M_PI;
			}
		}
	}
}

bool DEBUG = false;

void func(){

	Point mid_A = Point(0,0);

	for(int i = 0; i < N; i++){

		scanf("%lf %lf",&A[i].x,&A[i].y);
		mid_A = mid_A + A[i];
	}
	mid_A = mid_A/N;

	for(int i = 0; i < N; i++){

		A[i] = A[i]-mid_A;
	}
	sort(A,A+N);

	if(DEBUG){

		for(int i = 0; i < N; i++){

			printf("A[%d] ",i);
			A[i].debug();
		}
	}

	Point mid_B = Point(0,0);
	for(int i = 0; i < N; i++){

		scanf("%lf %lf",&B[i].x,&B[i].y);
		mid_B = mid_B + B[i];
	}

	mid_B = mid_B/N;
	for(int i = 0; i < N; i++){

		B[i] = B[i]-mid_B;
	}

	double ans = BIG_NUM;

	double base_rad = calc_rad(A[0]);

	if(DEBUG){

		printf("base_rad:%.3lf\n",base_rad);
	}

	for(int i = 0; i < N; i++){

		double tmp_rad = calc_rad(B[i]);
		for(int k = 0; k < N; k++){

			work[k] = rotate(Point(0,0),B[k],base_rad-tmp_rad);
		}
		sort(work,work+N);

		if(DEBUG){
			printf("\ni:%d\n",i);
			for(int k = 0; k < N; k++){

				work[k].debug();
			}
		}

		bool FLG = true;
		for(int k = 0; k < N; k++){
			if(A[k] == work[k]){

				//Do nothing

			}else{

				FLG = false;
				break;
			}
		}

		if(!FLG)continue;

		double diff = base_rad-tmp_rad;
		if(diff < 0){

			diff += 2*M_PI;
		}

		if(diff > M_PI){

			diff = 2*M_PI-diff;
		}

		if(DEBUG){

			printf("diff:%.3lf\n",diff);
		}

		ans = min(ans,diff);
	}

	printf("%.12lf\n",ans);
}

int main(){

	while(true){

		scanf("%d",&N);
		if(N == 0)break;

		func();
	}

	return 0;
}
accuracy: 1
time_ms: 110
memory_kb: 3780
final_rank: 17

code_snippet: #include <iostream>
#include <vector>
#include <array>
#include <string>
#include <stack>
#include <queue>
#include <deque>
#include <map>
#include <unordered_map>
#include <set>
#include <unordered_set>
#include <tuple>
#include <bitset>
#include <memory>
#include <cmath>
#include <algorithm>
#include <functional>
#include <iomanip>
#include <numeric>
#include <climits>
#include <cfloat>
struct Point {
	double x, y;
	struct Vector operator-(const Point& that) const;
	double distance_from(const Point& that) const;
};
struct Vector {
	double dx, dy;
	double dot(const Vector& that) const;
	double cross(const Vector& that)const;
	double length() const;
	struct Angle to_angle() const;
	struct Angle angle_with(const Vector& that) const;
	Vector rotate(const struct Angle& angle) const;
	Vector operator-(const Vector& that) const;
};
struct Angle {
	double sin, cos;
	double to_radian() const;
	Angle operator-() const;
};
int main() {
	std::vector<double> result;
	while (true) {
		int n; std::cin >> n; if (n == 0) break;
		std::vector<Point> before_points(n), after_points(n);
		for (auto& point : before_points) std::cin >> point.x >> point.y;
		for (auto& point : after_points) std::cin >> point.x >> point.y;
		if (n == 1) {
			//std::cout << 0 << '\n';
			result.push_back(0);
			continue;
		}
		const auto origin = *std::min_element(before_points.begin(), before_points.end(), [](const Point& a, const Point& b) {return (a.y != b.y) ? a.y < b.y : a.x < b.x; });
		std::vector<Vector> before_vec; before_vec.reserve(n - 1);
		for (const auto& point : before_points) {
			if (origin.distance_from(point) > 1e-9) before_vec.push_back(point - origin);
		}
		const auto base = *std::max_element(before_vec.begin(), before_vec.end(), [](const Vector& a, const Vector& b) {return std::abs(a.cross(b)) <= 1e-9 ? a.length() < b.length() : a.cross(b) < 0; });
		const auto angle = base.to_angle();
		for (auto& vec : before_vec) vec = vec.rotate(-angle); 
		std::sort(before_vec.begin(), before_vec.end(), [base](const Vector& a, const Vector& b) { return std::abs(a.cross(b)) < 1e-12 ? a.length() < b.length() : a.cross(b) < 0; });
		double min_radian = DBL_MAX;
		for (auto i = 0; i < n; ++i) {
			std::vector<Vector> after_mapped; after_mapped.reserve(n - 1);
			for (auto j = 0; j < n; ++j) if (i != j) after_mapped.push_back(after_points[j] - after_points[i]);
			const auto new_base = *std::max_element(after_mapped.begin(), after_mapped.end(), [](const Vector& a, const Vector& b) {return std::abs(a.cross(b)) <= 1e-9 ? a.length() < b.length() : a.cross(b) < 0; });
			const auto new_angle = new_base.to_angle();
			for (auto& vec : after_mapped) vec = vec.rotate(-new_angle);
			if (std::any_of(after_mapped.begin(), after_mapped.end(), [](const Vector& a) {return a.dy < -1e-9; }))
				continue;
			std::sort(after_mapped.begin(), after_mapped.end(), [](const Vector& a, const Vector& b) { return std::abs(a.cross(b)) < 1e-12 ? a.length() < b.length() : a.cross(b) < 0; });
			bool is_match = true;
			for (auto j = 0; j < n - 1; ++j) {
				if ((after_mapped[j] - before_vec[j]).length() > 1e-6) {
					is_match = false;
					break;
				}
			}
			if (is_match) {
				min_radian = std::min(min_radian, std::acos(base.angle_with(new_base).cos));
			}
		}
		//std::cout << std::setprecision(15) << std::fixed << min_radian << '\n';
		result.push_back(min_radian);
	}
	for (const auto r : result) {
		std::cout << std::setprecision(10) << std::fixed << r << '\n';
	}
}


Vector Point::operator-(const Point& that) const
{
	return Vector{ x - that.x, y - that.y };
}

double Point::distance_from(const Point& that) const
{
	return (*this - that).length();
}

double Vector::dot(const Vector& that) const
{
	return dx * that.dx + dy * that.dy;
}

double Vector::cross(const Vector& that) const
{
	return dx * that.dy - dy * that.dx;
}

double Vector::length() const
{
	return std::sqrt(dx * dx + dy * dy);
}

Angle Vector::to_angle() const
{
	const auto len = length();
	return Angle{ dy / len, dx / len };
}

Angle Vector::angle_with(const Vector& that) const
{
	const auto len = length() * that.length();
	return Angle{ cross(that) / len, dot(that) / len };
}

Vector Vector::rotate(const Angle& angle) const
{
	return Vector{ dx * angle.cos - dy * angle.sin, dy * angle.cos + dx * angle.sin };
}

Vector Vector::operator-(const Vector& that) const
{
	return Vector{ dx - that.dx, dy - that.dy };
}

double Angle::to_radian() const
{
	return (sin >= 0) ? std::acos(cos) : std::acos(-1) * 2 - std::acos(cos);
}

Angle Angle::operator-() const
{
	return Angle{ -sin, cos };
}
accuracy: 1
time_ms: 40
memory_kb: 3460
final_rank: 11

code_snippet: #include<iostream>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<algorithm>
#include<functional>
#include<iomanip>
#include<queue>
#include<ciso646>
#include<random>
#include<map>
#include<set>
#include<complex>
#include<bitset>
#include<stack>
#include<unordered_map>
#include<utility>
#include<cassert>
using namespace std;

typedef long long ll;

typedef unsigned long long ul;
typedef unsigned int ui;
const ll mod = 1000000007;
typedef long double ld;
typedef complex<ld> Point;
const ll INF = mod * mod;
typedef pair<int, int> P;
#define stop char nyaa;cin>>nyaa;
#define rep(i,n) for(int i=0;i<n;i++)
#define per(i,n) for(int i=n-1;i>=0;i--)
#define Rep(i,sta,n) for(int i=sta;i<n;i++)
#define rep1(i,n) for(int i=1;i<=n;i++)
#define per1(i,n) for(int i=n;i>=1;i--)
#define Rep1(i,sta,n) for(int i=sta;i<=n;i++)
const ld eps = 1e-4;
const ld pi = acos(-1.0);
typedef pair<ld, ld> LDP;
typedef pair<ll, ll> LP;
typedef vector<int> vec;
typedef vector<string> svec;

bool eq(ld a, ld b) {
	return (abs(a - b) < eps);
}

class Line {
public:
	Point a, b;
};
class Circle {
public:
	Point p; ld r;
};

ld dot(Point a, Point b) {
	return real(conj(a)*b);
}
ld cross(Point a, Point b) {
	return imag(conj(a)*b);
}
namespace std {
	bool operator<(const Point &lhs, const Point &rhs) {
		return lhs.real() == rhs.real() ? lhs.imag() < rhs.imag() : lhs.real() < rhs.real();
	}
}
Point proj(Line l, Point p) {
	ld t = dot(p - l.a, l.a - l.b) / norm(l.a - l.b);
	return l.a + t * (l.a - l.b);
}

ld dist_lp(Line l, Point p) {
	return abs(p - proj(l, p));
}

int ccw(Point a, Point b, Point c) {
	b -= a; c -= a;
	if (cross(b, c) > eps)return 1;//a,b,cが反時計回り
	if (cross(b, c) < -eps)return -1;//a,b,cが時計回り
	if (dot(b, c) < 0)return 2;//c,a,bの順に一直線
	if (norm(b) < norm(c))return -2;//a,b,cの順に一直線
	return 0;//a,c,bの順に一直線
}
bool isis_ll(Line l, Line m) {
	return !eq(cross(l.b - l.a, m.b - m.a), 0);
}
Point is_ll(Line s, Line t) {
	Point sv = s.b - s.a; Point tv = t.b - t.a;
	return s.a + sv * cross(tv, t.a - s.a) / cross(tv, sv);
}

//直線lに幅dをつける
vector<Line> make_w(Line l, ld d) {
	Point dif = l.b - l.a;
	dif = dif*Point{0, 1};
	dif = dif * (d / abs(dif));
	vector<Line> ret;
	for (int id = 1; id >= -1; id -= 2) {
		Point a = l.a + dif * (ld)id;
		Point b = l.b + dif * (ld)id;
		ret.push_back({ a,b });
	}
	return ret;
}

typedef vector<Point> polygon;
polygon ConvexHull(polygon p) {
	int n = p.size();
	int k = 0;
	sort(p.begin(), p.end());
	polygon ch(2 * n);
	for (int i = 0; i < n; ch[k++] = p[i++]) {
		while (k >= 2 && ccw(ch[k - 2], ch[k - 1], p[i]) <= 0)--k;
	}
	for (int i = n - 2, t = k + 1; i >= 0; ch[k++] = p[i--]) {
		while (k >= t && ccw(ch[k - 2], ch[k - 1], p[i]) <= 0)--k;
	}
	ch.resize(k - 1);
	return ch;
}
polygon convex_cut(const polygon &p, Line l) {
	vector<Point> ret;
	rep(i, p.size()) {
		Point a = p[i], b = p[(i + 1) % p.size()];
		if (ccw(l.a, l.b, a) != -1)ret.push_back(a);
		if (ccw(l.a, l.b, a)*ccw(l.a, l.b, b)<0) {
			ret.push_back(is_ll({ a,b }, l));
		}
	}
	return ret;
}
ld area(const polygon &p){
	ld ret = 0;
	int n = p.size();
	rep(j, n)ret += cross(p[j], p[(j + 1) % n]);
	return ret / 2.0;
}
ld max_distance(const polygon &p) {
	//assert(p.size()>1);
	polygon g = ConvexHull(p);
	int n = g.size(), a = 0, b = 1;
	ld ret = abs(g[0] - g[1]);
	while (a < n) {
		Point p1 = g[a%n], p2 = g[(a + 1) % n];
		Point q1 = g[b%n], q2 = g[(b + 1) % n];
		if (arg((p2 - p1) / (q1 - q2)) > 0)++b; else ++a;
		ret = max(ret, abs(p1 - q1));
	}
	return ret;
}

vector<Point> is_cc(Circle c1, Circle c2) {
	vector<Point> res;
	ld d = abs(c1.p - c2.p);
	ld rc = (d*d + c1.r*c1.r - c2.r*c2.r) / (2 * d);
	ld dfr = c1.r*c1.r - rc * rc;
	if (abs(dfr) < eps)dfr = 0.0;
	if (dfr < 0.0)return res;
	ld rs = sqrt(dfr);
	Point diff = (c2.p - c1.p) / d;
	res.push_back(c1.p + diff * Point(rc, rs));
	if (dfr != 0.0)res.push_back(c1.p + diff * Point(rc, -rs));
	return res;
}
bool in_Circle(Circle a, Circle b) {
	ld dist = abs(b.p - a.p);
	return dist < b.r - a.r+eps;
}

ll gcd(ll x, ll y) {
	x = abs(x), y = abs(y);
	if (x < y)swap(x, y);
	while (y) {
		ll r = x % y; x = y; y = r;
	}
	return x;
}

//0/0だけ気を付けて！
struct ratio {
	ll a, b;
	ratio(ll x) { a = x; b = 1; };
	ratio(ll x, ll y) {
		a = x; b = y;
		ll g = gcd(x, y);
		if (g > 0) {
			a /= g, b /= g;
			if (b < 0)a = -a, b = -b;
		}
	};

};

void normalize(ratio &r) {
	ll g = gcd(r.a, r.b);
	r.a /= g; r.b /= g;
	if (r.b < 0)r.b = -r.b, r.a = -r.a;
}
bool operator<(const ratio &x, const ratio &y) {
	return x.a*y.b < x.b*y.a;
}
bool operator==(const ratio &x, const ratio &y) {
	return x.a*y.b == x.b*y.a;
}

bool isis_cc(Circle a, Circle b) {
	ld dist = abs(b.p - a.p);
	return dist < a.r + b.r;
}
int n;

bool same(vector<Point> &a, vector<Point> &b, Point c, ld theta) {
	vector<Point>u;
	rep(i, n) {
		Point dif = a[i] - a[0];
		dif = dif * Point{ cos(theta),sin(theta) };
		Point nex = a[0] + dif + c;
		u.push_back(nex);
	}
	sort(u.begin(), u.end());
	rep(i, n) {
		if (abs(u[i] - b[i]) > eps)return false;
	}
	return true;
}
void solve() {
	vector<Point> a(n), b(n);
	rep(i, n) {
		ld x, y; cin >> x >> y;
		a[i] = { x,y };
	}
	rep(i, n) {
		ld x, y; cin >> x >> y;
		b[i] = { x,y };
	}
	sort(b.begin(), b.end());
	ld ans = mod;
	rep(i, n) {
		rep(j, n) {
			if (i == j)continue;
			ld dist = abs(b[i] - b[j]);
			if (!eq(dist,abs(a[0] - a[1])))continue;
			Point c = b[i] - a[0];
			ld t1 = arg(a[1] - a[0]);
			ld t2 = arg(b[j] - b[i]);
			ld t = t2 - t1;
			//cout << t2 << " "<<t1 << endl;
			while (t > 2 * pi)t -= 2 * pi;
			while (t < 0)t += 2 * pi;
			if (eq(t, 2*pi))t = 0;
			//cout << t << endl;
			if (same(a, b, c, t)) {
				ans = min(ans, t);
				ans = min(ans, 2 * pi - t);
			}
		}
	}
	if (ans == mod)ans = 0;
	cout << ans << endl;
}

signed main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout << fixed << setprecision(11);
	while (cin >> n, n) {
		solve();
	}
	//solve();
	//stop
	return 0;
}
accuracy: 1
time_ms: 240
memory_kb: 3656
final_rank: 19

code_snippet: #include<iomanip>
#include<limits>
#include<thread>
#include<utility>
#include<iostream>
#include<string>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<stack>
#include<queue>
#include<cmath>
#include<numeric>
#include<cassert>
#include<random>
#include<chrono>
#include<unordered_set>
#include<unordered_map>
#include<fstream>
#include<list>
#include<functional>
#include<bitset>
#include<complex>
#include<tuple>
using namespace std;
typedef unsigned long long int ull;
typedef long long int ll;
typedef pair<ll,ll> pll;
typedef long double D;
typedef complex<D> P;
#define F first
#define S second
const ll E=1e18+7;
const ll MOD=1000000007;


template<typename T,typename U>istream & operator >> (istream &i,pair<T,U> &A){i>>A.F>>A.S; return i;}
template<typename T>istream & operator >> (istream &i,vector<T> &A){for(auto &I:A){i>>I;} return i;}
template<typename T,typename U>ostream & operator << (ostream &o,pair<T,U> &A){o<<A.F<<" "<<A.S; return o;}
template<typename T>ostream & operator << (ostream &o,vector<T> &A){ll i=A.size(); for(auto &I:A){o<<I<<(--i?" ":"");} return o;}
template<typename T>vector<T> & cset(vector<T> &A,T e=T()){for(auto &I:A){I=e;} return A;}

namespace Geometry{
    typedef long double D;
    typedef complex<long double> P;
    typedef pair<P,D> C;
    
    const D EPS=1e-9;
    const D PI=asin(1)*2;
    const D INF=1e18;
    
    const static bool comp(const P &p1,const P &p2){return p1.real()==p2.real()?p1.imag()<p2.imag():p1.real()<p2.real();}
    
    D dot(P p1,P p2){return p1.real()*p2.real()+p1.imag()*p2.imag();}
    
    D cross(P p1,P p2){return p1.real()*p2.imag()-p1.imag()*p2.real();}
    
    P project(P vec,P x){return vec*(x/vec).real();}
    
    P project(P p1,P p2,P x){return p1+project(p2-p1,x-p1);}
    
    P reflect(P vec,P x){return vec*conj(x/vec);}
    
    P reflect(P p1,P p2,P x){return p1+reflect(p2-p1,x-p1);}
    
    bool intersectSL(P p1,P p2,P vec){vec/=abs(vec); p1/=vec; p2/=vec; return (p1.imag()<EPS && p2.imag()>-EPS) || (p1.imag()>-EPS && p2.imag()<EPS);}
    
    bool intersectSL(P p1,P p2,P p3,P p4){return intersectSL(p1-p4,p2-p4,p3-p4);}
    
    bool intersectSS(P p1,P p2,P p3,P p4){return (dot(p2-p1,p3-p1)<-EPS && dot(p2-p1,p4-p1)<-EPS) || (dot(p1-p2,p3-p2)<-EPS && dot(p1-p2,p4-p2)<-EPS)?false:intersectSL(p1,p2,p3,p4) && intersectSL(p3,p4,p1,p2);}
    
    D distLP(P vec,P x){return abs((x/vec).imag())*abs(vec);}
    
    D distLP(P p1,P p2,P x){return distLP(p2-p1,x-p1);}
    
    D distSP(P p1,P p2,P x){return dot(p2-p1,x-p1)<-EPS?abs(x-p1):dot(p1-p2,x-p2)<-EPS?abs(x-p2):distLP(p1,p2,x);}
    
    D distSS(P p1,P p2,P p3,P p4){return intersectSS(p1,p2,p3,p4)?0.0:min(min(distSP(p1,p2,p3),distSP(p1,p2,p4)),min(distSP(p3,p4,p1),distSP(p3,p4,p2)));}
    
    P crosspointLL(P p1,P p2,P vec){return abs(cross(p2-p1,vec))<EPS?vec:vec*cross(p2-p1,p2)/cross(p2-p1,vec);}
    
    P crosspointLL(P p1,P p2,P p3,P p4){return p4+crosspointLL(p1-p4,p2-p4,p3-p4);}
    
    P crosspointSS(P p1,P p2,P p3,P p4){return distSP(p1,p2,p3)<EPS?p3:distSP(p1,p2,p4)<EPS?p4:crosspointLL(p1,p2,p3,p4);}
    
    bool intersectShL(P p1,P p2,P vec){vec/=abs(vec); return intersectSL(p1,p2,vec) && crosspointLL(p1/vec,p2/vec,vec/vec).real()>-EPS;}
    
    bool intersectShL(P p1,P p2,P p3,P p4){return intersectShL(p1-p3,p2-p3,p4-p3);}
    
    //1::in,0::on edge,-1::out
    int contain(const vector<P> &poly,const P &p){
        vector<P> A={{65537,96847},{-24061,6701},{56369,-86509},{-93763,-78049},{56957,10007}};
        vector<bool> cnt(5,false);
        for(int i=1;i<=poly.size();i++){
            if(distSP(poly[i-1],poly[i%poly.size()],p)<EPS){return 0;}
            for(int j=0;j<5;j++){
                if(intersectShL(poly[i-1],poly[i%poly.size()],p,p+A[j])){cnt[j]=!cnt[j];}
            }
        }
        int in=0;
        for(int j=0;j<5;j++){if(cnt[j]){in++;}}
        return in>=3?1:-1;
    }
    
    vector<P> convexcut(const vector<P> &poly,P p1,P p2){
        vector<P> ret;
        for(int i=1;i<=poly.size();i++){
            if(cross(p2-p1,poly[i-1]-p1)>-EPS){ret.push_back(poly[i-1]);}
            if(intersectSL(poly[i-1],poly[i%poly.size()],p1,p2) && distLP(p1,p2,poly[i-1])>EPS && distLP(p1,p2,poly[i%poly.size()])>EPS){ret.push_back(crosspointLL(poly[i-1],poly[i%poly.size()],p1,p2));}
        }
        return ret;
    }
    
    D area(const vector<P> &poly){
        D ans=0;
        for(int i=2;i<poly.size();i++){ans+=cross(poly[i-1]-poly[0],poly[i]-poly[0]);}
        return abs(ans)/2;
    }
    
    vector<P> convexhull(vector<P> pts){
        vector<P> ret;
        sort(pts.begin(),pts.end(),comp);
        for(auto &I:pts){
            if(!ret.empty() && I==ret.back()){continue;}
            while(ret.size()>=2 && cross(ret.back()-ret[ret.size()-2],I-ret.back())<-EPS){ret.pop_back();}
            ret.push_back(I);
        }
        reverse(pts.begin(),pts.end());
        for(auto &I:pts){
            if(!ret.empty() && I==ret.back()){continue;}
            while(ret.size()>=2 && cross(ret.back()-ret[ret.size()-2],I-ret.back())<-EPS){ret.pop_back();}
            ret.push_back(I);
        }
        if(ret[0]==ret.back()){ret.pop_back();}
        return ret;
    }
    
    //4::seperate,3::circumscribe,2::intersect,1::inscribe,0::contain,-1::same
    int intersectCC(C c1,C c2){
        D d=abs(c1.F-c2.F),r=c1.S+c2.S,dif=abs(c2.S-c1.S);
        if(d<EPS && dif<EPS){return -1;}
        if(d-r>EPS){return 4;}
        if(d-r>-EPS){return 3;}
        if(d-dif>EPS){return 2;}
        if(d-dif>-EPS){return 1;}
        return 0;
    }
    
    vector<P> crosspointLC(P p1,P p2,C c){
        vector<P> ret;
        P pr=project(p1,p2,c.F);
        D d=distLP(p1,p2,c.F);
        if(d-c.S>EPS){return ret;}
        if(d-c.S>-EPS){ret.push_back(pr); return ret;}
        P vec=p2-p1; vec*=sqrt(c.S*c.S-d*d)/abs(vec);
        ret.push_back(pr-vec);
        ret.push_back(pr+vec);
        return ret;
    }
    
    vector<P> crosspointSC(P p1,P p2,C c){
        vector<P> ret;
        for(auto &I:crosspointLC(p1,p2,c)){if(distSP(p1,p2,I)<EPS){ret.push_back(I);}}
        return ret;
    }
    
    vector<P> crosspointCC(C c1,C c2){
        vector<P> ret;
        P vec=c2.F-c1.F;
        D base=(c1.S*c1.S+norm(vec)-c2.S*c2.S)/(2*abs(vec));
        D h=sqrt(c1.S*c1.S-base*base);
        vec/=abs(vec);
        ret.push_back(c1.F+vec*P(base,-h));
        ret.push_back(c1.F+vec*P(base,h));
        return ret;
    }
    
    vector<P> tangentCP(C c,P p){return crosspointCC(c,C(p,sqrt(norm(c.F-p)-c.S*c.S)));}
    
    vector<pair<P,P>> tangentCC(C c1,C c2){
        vector<pair<P,P>> ret;
        P d=c2.F-c1.F;
        for(D i:{-1,1}){
            D r=c1.S+c2.S*i;
            if(intersectCC(c1,c2)>i+1){
                for(P s:{-1i,1i}){
                    P p=r+s*sqrt(norm(d)-norm(r));
                    ret.push_back({c1.F+d*c1.S/norm(d)*p,c2.F-d*i*c2.S/norm(d)*p});
                }
            }
        }
        return ret;
    }
    
    D area(const vector<P> &poly,C c){
        D ret=0;
        for(int i=0;i<poly.size();i++){
            P a=poly[i]-c.F,b=poly[(i+1)%poly.size()]-c.F;
            if(abs(a)<c.S+EPS && abs(b)<c.S+EPS){ret+=cross(a,b);}
            else{
                vector<P> A=crosspointSC(a,b,{0,c.S});
                if(A.empty()){ret+=c.S*c.S*arg(b/a);}
                else{
                    ret+=(abs(a)<c.S?cross(a,A[0]):c.S*c.S*arg(A[0]/a));
                    ret+=(abs(b)<c.S?cross(A.back(),b):c.S*c.S*arg(b/A.back()));
                    ret+=cross(A[0],A.back());
                }
            }
        }
        return abs(ret)/2;
    }
    
    //反時計回り
    D diameter(const vector<P> &poly){
        D ret=0;
        ll l=0,r=0,n=poly.size();
        if(n==2){return abs(poly[0]-poly[1]);}
        for(int i=0;i<n;i++){
            if(comp(poly[l],poly[i])){l=i;}
            if(comp(poly[i],poly[r])){r=i;}
        }
        ll sl=r,sr=l;
        while(sl!=l || sr!=r){
            ret=max(ret,abs(poly[r]-poly[l]));
            if(cross(poly[(l+1)%n]-poly[l],poly[(r+1)%n]-poly[r])<0){(++l)%=n;}
            else{(++r)%=n;}
        }
        return ret;
    }
    
    D closestpair(vector<P> pt){
        sort(pt.begin(),pt.end(),comp);
        D ret=INF;
        for(ll i=1;i<pt.size();i<<=1){
            for(ll j=0;i+j<pt.size();j+=i*2){
                ll m=i+j;
                vector<P> R;
                D l=-INF,r=INF;
                for(ll k=j;k<m;k++){l=max(l,pt[k].real());}
                for(ll k=0;m+k<pt.size() && k<i;k++){r=min(r,pt[m+k].real());}
                for(ll k=0;m+k<pt.size() && k<i;k++){if(pt[m+k].real()-l<ret){R.push_back(pt[m+k]);}}
                ll idx=0;
                for(ll k=j;k<m;k++){
                    if(r-pt[k].real()>ret){continue;}
                    while(idx<R.size() && pt[k].imag()-R[idx].imag()>ret){idx++;}
                    for(ll n=idx;n<R.size() && R[n].imag()-pt[k].imag()<ret;n++){ret=min(ret,abs(R[n]-pt[k]));}
                }
                inplace_merge(pt.begin()+j,pt.begin()+m,j+i*2<pt.size()?pt.begin()+j+2*i:pt.end(),[](const P &a,const P &b){return a.imag()==b.imag()?a.real()<b.real():a.imag()<b.imag();});
            }
        }
        return ret;
    }
    
    P centerofgravity(const vector<P> &pt){
        P ret(0,0);
        D wt=0;
        for(int i=2;i<pt.size();i++){
            D w2=cross(pt[i-1]-pt[0],pt[i]-pt[0]);
            P p=(pt[0]+pt[i-1]+pt[i])/(D)3;
            wt+=w2;
            ret+=p*w2;
        }
        return ret/wt;
    }
    
    istream & operator >> (istream &i,P &p){D x,y; i>>x>>y; p={x,y}; return i;}
    istream & operator >> (istream &i,C &p){D x,y; i>>x>>y>>p.S; p.F={x,y}; return i;}
};

using namespace Geometry;




int main(){
    ll n;
    while(cin>>n,n){
        vector<P> A(n),B(n);
        cin>>A>>B;
        P mid1(0,0),mid2(0,0);
        for(auto &I:A){mid1+=I;} mid1/=n;
        for(auto &I:B){mid2+=I;} mid2/=n;
        for(auto &I:A){I-=mid1;}
        for(auto &I:B){I-=mid2;}
        sort(A.begin(),A.end(),[](P a,P b){return arg(a)+EPS<arg(b) || (abs(arg(a)-arg(b))<EPS*2 && abs(a)<abs(b));});
        sort(B.begin(),B.end(),[](P a,P b){return arg(a)+EPS<arg(b) || (abs(arg(a)-arg(b))<EPS*2 && abs(a)<abs(b));});
        //cout<<A<<endl<<B<<endl;
        D ans=E;
        ll k=-1;
        for(int i=0;i<n;i++){if(abs(B[i])>EPS){k=i;}}
        for(int i=0;i<n;i++){if(abs(B[i])>1){k=i;}}
        if(k==-1){ans=0;}
        for(int i=0;i<n && k!=-1;i++){
            D dif=0;
            P vec=A[i]/abs(A[i])/(B[k]/abs(B[k]));
            for(int j=0;j<n;j++){
                dif+=abs(A[(i+j)%n]/vec-B[(k+j)%n]);
            }
            if(dif<EPS*n){ans=min(ans,abs(arg(vec)));}
        }
        cout<<fixed<<setprecision(12)<<ans<<endl;
    }
    return 0;
}
accuracy: 1
time_ms: 130
memory_kb: 3388
final_rank: 15

code_snippet: #include <iostream>
#include <iomanip>
#include <complex>
#include <vector>
#include <algorithm>
#include <cmath>
#include <set>
using namespace std;
const double EPS = 1e-8;
const double INF = 1e12;
const double PI = acos(-1);
#define EQ(n,m) (abs((n)-(m)) < EPS)
#define X real()
#define Y imag()

typedef complex<double> P;
typedef vector<P> VP;
namespace std{
    bool operator < (const P& a, const P& b){
        return !EQ(a.X,b.X) ? a.X<b.X : a.Y+EPS<b.Y;
    }
    bool operator == (const P& a, const P& b){
        return abs(a-b) < EPS;
    }
}

double dot(P a, P b){
    return (conj(a)*b).X;
}
double cross(P a, P b){
    return (conj(a)*b).Y;
}
int ccw(P a, P b, P c){
    b -= a;
    c -= a;
    if(cross(b,c) > EPS) return +1; //ccw
    if(cross(b,c) < -EPS) return -1; //cw
    if(dot(b,c) < -EPS) return +2; //c-a-b
    if(abs(c)-abs(b) > EPS) return -2; //a-b-c
    return 0; //a-c-b
}
P rotate(const P &p, double rad){
    return p *P(cos(rad), sin(rad));
}

int main(){
    while(1){
        int n;
        cin >> n;
        if(n==0) break;

        if(n==1){
            double d;
            cin >> d >> d >> d >> d;
            cout << 0 << endl;
            continue;
        }

        //重心を原点に平行移動
        vector<VP> p(2, VP(n));
        for(int d=0; d<2; d++){
            P centroid(0, 0);
            for(int i=0; i<n; i++){
                double x,y;
                cin >> x >> y;
                p[d][i] = P(x, y);
                centroid += p[d][i];
            }
            centroid /= n;
            //p0が重心に重なると角度が取れなくなるので例外処理
            if(p[d][0] == centroid){
                swap(p[d][0], p[d][1]);
            }
            for(int i=0; i<n; i++){
                p[d][i] -= centroid;
            }
        }

        //同じ点が2点以上ないという仮定で、全部このsetに入って入ればokとする
        set<P> pset;
        for(int i=0; i<n; i++){
            pset.insert(p[0][i]);
        }
        double ans = INF;
        for(int i=0; i<n; i++){
            //p[1][i]を回転させてp[0][0]に合わせる
            if(!EQ(abs(p[0][0]), abs(p[1][i]))) continue;
            double angle = arg(p[1][i]/p[0][0]);
            bool ok = true;
            for(int j=0; j<n; j++){
                P rot = rotate(p[1][j], -angle);
                if(pset.find(rot) == pset.end()){
                    ok = false;
                    break;
                }
            }
            if(ok){
                ans = min(ans, abs(angle));
            }
        }
        cout << fixed << setprecision(10);
        cout << ans << endl;
    }
    return 0;
}
accuracy: 1
time_ms: 30
memory_kb: 3756
final_rank: 14

code_snippet: #include "bits/stdc++.h"
#include<unordered_map>
#include<unordered_set>
#pragma warning(disable:4996)
using namespace std;
using ld = long double;
const ld eps = 1e-9;



/* 幾何の基本 */

#include <complex>

typedef complex<ld> Point;


const ld pi = acos(-1.0);
const ld dtop = pi / 180.;
const ld ptod = 1. / dtop;

namespace std {
	bool operator<(const Point &lhs, const Point &rhs) {
		if (lhs.real() < rhs.real() - eps) return true;
		if (lhs.real() > rhs.real() + eps) return false;
		return lhs.imag() < rhs.imag();
	}
}

// 点の入力
Point input_Point() {
	ld x, y;
	cin >> x >> y;
	return Point(x, y);
}

// 誤差つき等号判定
bool eq(const ld a, const ld b) {
	return (abs(a - b) < eps);
}

// 内積
ld dot(const Point& a, const Point& b) {
	return real(conj(a) * b);
}

// 外積
ld cross(const Point& a, const Point& b) {
	return imag(conj(a) * b);
}

// 直線の定義
class Line {
public:
	Point a, b;
	Line() : a(Point(0, 0)), b(Point(0, 0)) {}
	Line(Point a, Point b) : a(a), b(b) {}
	Point operator[](const int _num)const {
		if (_num == 0)return a;
		else if (_num == 1)return b;
		else {
			assert(false);
			return Point();
		}
	}
};

// 円の定義
class Circle {
public:
	Point p;
	ld r;
	Circle() : p(Point(0, 0)), r(0) {}
	Circle(Point p, ld r) : p(p), r(r) {}
};

// ccw
// 1: a,b,cが反時計周りの順に並ぶ
//-1: a,b,cが時計周りの順に並ぶ
// 2: c,a,bの順に直線に並ぶ
//-2: a,b,cの順に直線に並ぶ
// 0: a,c,bの順に直線に並ぶ
int ccw(const Point& a, const Point &b, const Point &c) {
	const Point nb(b - a);
	const Point nc(c - a);
	if (cross(nb, nc) > eps) return 1;   // a,b,cが反時計周りの順に並ぶ
	if (cross(nb, nc) < -eps) return -1; // a,b,cが時計周りの順に並ぶ
	if (dot(nb, nc) < 0) return 2;       // c,a,bの順に直線に並ぶ
	if (norm(nb) < norm(nc)) return -2;  // a,b,cの順に直線に並ぶ
	return 0;                          // a,c,bの順に直線に並ぶ
}


/* 交差判定 */

// 直線と直線の交差判定
bool isis_ll(const Line& l, const Line& m) {
	return !eq(cross(l.b - l.a, m.b - m.a), 0);
}

// 直線と線分の交差判定
bool isis_ls(const Line& l, const Line& s) {
	return isis_ll(l, s) &&
		(cross(l.b - l.a, s.a - l.a) * cross(l.b - l.a, s.b - l.a) < eps);
}

// 線分と線分の交差判定
bool isis_ss(const Line& s, const Line& t) {
	return ccw(s.a, s.b, t.a) * ccw(s.a, s.b, t.b) <= 0 &&
		ccw(t.a, t.b, s.a) * ccw(t.a, t.b, s.b) <= 0;
}

// 点の直線上判定
bool isis_lp(const Line& l, const Point& p) {
	return (abs(cross(l.b - p, l.a - p)) < eps);
}

// 点の線分上判定
bool isis_sp(const Line& s, const Point& p) {
	return (abs(s.a - p) + abs(s.b - p) - abs(s.b - s.a) < eps);
}

// 垂線の足
Point proj(const Line &l, const Point& p) {
	ld t = dot(p - l.a, l.b - l.a) / norm(l.a - l.b);
	return l.a + t * (l.b - l.a);
}

//線対象の位置にある点
Point reflect(const Line &l, const Point &p) {
	Point pr = proj(l, p);
	return pr * 2.l - p;
}

// 直線と直線の交点
Point is_ll(const Line &s, const Line& t) {
	Point sv = s.b - s.a, tv = t.b - t.a;
	assert(cross(sv, tv) != 0);
	return s.a + sv * cross(tv, t.a - s.a) / cross(tv, sv);
}
// 直線と直線の交点
vector<Point> is_ll2(const Line &s, const Line& t) {
	Point sv = s.b - s.a, tv = t.b - t.a;
	if (cross(sv, tv) != 0)return vector<Point>(1, is_ll(s, t));
	else {
		vector<Point>ans;
		for (int k = 0; k < 2; ++k) {
			if (isis_sp(s, t[k]) && find(ans.begin(), ans.end(), t[k]) == ans.end())ans.push_back(t[k]);
			if (isis_sp(t, s[k]) && find(ans.begin(), ans.end(), s[k]) == ans.end())ans.push_back(s[k]);
		}
		return ans;
	}
}
// 線分と線分の交点
//　重なってる部分あるとassert(false)
Point is_ss(const Line &s, const Line& t) {
	if (isis_ss(s, t)) {
		for (int k = 0; k < 2; ++k) {
			for (int l = 0; l < 2; ++l) {
				if (s[k] == t[l])return s[k];
			}
		}
		return is_ll(s, t);
	}
	else {
		//先にisis_ssしてね
		assert(false);
		return Point(0, 0);
	}
}
// 線分と線分の交点
vector<Point> is_ss2(const Line &s, const Line& t) {
	vector<Point> kouho(is_ll2(s, t));
	vector<Point>ans;
	for (auto p : kouho) {
		if (isis_sp(s, p) && isis_sp(t, p))ans.emplace_back(p);
	}
	return ans;
}
// 直線と点の距離
ld dist_lp(const Line& l, const Point& p) {
	return abs(p - proj(l, p));
}

//直線と直線の距離
ld dist_ll(const Line& l, const Line& m) {
	return isis_ll(l, m) ? 0 : dist_lp(l, m.a);
}

// 直線と線分の距離
ld dist_ls(const Line& l, const Line& s) {
	return isis_ls(l, s) ? 0 : min(dist_lp(l, s.a), dist_lp(l, s.b));
}

// 線分と点の距離
ld dist_sp(const Line& s, const Point& p) {
	Point r = proj(s, p);
	return isis_sp(s, r) ? abs(r - p) : min(abs(s.a - p), abs(s.b - p));
}

// 線分と線分の距離
ld dist_ss(const Line& s, const Line& t) {
	if (isis_ss(s, t)) return 0;
	return min({ dist_sp(s, t.a), dist_sp(s, t.b), dist_sp(t, s.a), dist_sp(t, s.b) });
}


//直線と直線の二等分線のベクトル
Line line_bisection(const Line &s, const Line &t) {
	const Point laglanju(is_ll(s, t));
	const Point avec = !(abs(laglanju - s[0])<eps) ? s[0] - laglanju : s[1] - laglanju;
	const Point bvec = !(abs(laglanju - t[0])<eps) ? t[0] - laglanju : t[1] - laglanju;

	return Line(laglanju, laglanju + (abs(bvec)*avec + abs(avec)*bvec) / (abs(avec) + abs(bvec)));
}
//点と点の垂直二等分線　aを左に見ながら
Line point_bisection(const Point&a, const Point&b) {
	const Point cen((a + b) / 2.l);
	const Point vec = (b - a)*Point(0, 1);
	return Line(cen, cen + vec);
}

//三つの点からなる外心
Point outer_center(const vector<Point>&ps) {
	assert(ps.size() == 3);
	Line l1 = point_bisection(ps[0], ps[1]);
	Line l2 = point_bisection(ps[1], ps[2]);
	return is_ll(l1, l2);
}


//三つの直線からなる内心
//三つの直線が並行でないことは確かめといてね
Point  inner_center(const vector<Line>&ls) {
	vector<Point>vertics;
	for (int i = 0; i <static_cast<int>(ls.size()); ++i) {
		vertics.push_back(is_ll(ls[i], ls[(i + 1) % 3]));
	}
	if (vertics[0] == vertics[1] || vertics[1] == vertics[2] || vertics[2] == vertics[0])return vertics[0];
	Line bi1(line_bisection(Line(vertics[0], vertics[1]), Line(vertics[0], vertics[2])));
	Line bi2(line_bisection(Line(vertics[1], vertics[2]), Line(vertics[1], vertics[0])));
	if (bi1[0] == bi2[0])return bi1[0];
	else {
		return is_ll(bi1, bi2);
	}
}

//三つの直線からなる傍心
//三つの直線が並行でないことは確かめといてね
vector<Point>  ex_center(const vector<Line>&ls) {
	vector<Point>vertics;
	for (int i = 0; i < static_cast<int>(ls.size()); ++i) {
		vertics.push_back(is_ll(ls[i], ls[(i + 1) % 3]));
	}
	if (abs(vertics[0] - vertics[1])<eps || abs(vertics[1] - vertics[2])<eps || (abs(vertics[2] - vertics[0])<eps))return vector<Point>();
	vector<Point>ecs;
	for (int i = 0; i < 3; ++i) {
		Line bi1(line_bisection(Line(vertics[i], vertics[i] * 2.0l - vertics[(i + 2) % 3]), Line(vertics[i], vertics[(i + 1) % 3])));
		Line bi2(line_bisection(Line(vertics[(i + 1) % 3], vertics[(i + 1) % 3] * 2.0l - vertics[(i + 2) % 3]), Line(vertics[(i + 1) % 3], vertics[i])));
		ecs.push_back(is_ll(bi1, bi2));
	}
	return ecs;
}


//a,b:並行
//c:並行でない
//三つの直線から同距離の位置を求める。
vector<Point>  same_dis(const vector<Line>&ls) {
	vector<Point>vertics;
	vertics.push_back(is_ll(ls[0], ls[2]));
	vertics.push_back(is_ll(ls[1], ls[2]));

	if (abs(vertics[0] - vertics[1]) < eps)return vector<Point>{vertics[0]};
	Line bis(line_bisection(ls[0], ls[1]));
	vector<Point>ecs;

	Line abi(line_bisection(Line(vertics[0], vertics[1]), ls[0]));
	ecs.push_back(is_ll(bis, abi));


	Line bbi(line_bisection(Line(vertics[0], 2.l*vertics[0] - vertics[1]), ls[0]));
	ecs.push_back(is_ll(bis, bbi));

	return ecs;
}
/* 円 */

// 円と円の交点
vector<Point> is_cc(const Circle& c1, const Circle& c2) {
	vector<Point> res;
	ld d = abs(c1.p - c2.p);
	ld rc = (d * d + c1.r * c1.r - c2.r * c2.r) / (2 * d);
	ld dfr = c1.r * c1.r - rc * rc;
	if (abs(dfr) < eps) dfr = 0.0;
	else if (dfr < 0.0) return res; // no intersection
	ld rs = sqrt(dfr);
	Point diff = (c2.p - c1.p) / d;
	res.push_back(c1.p + diff * Point(rc, rs));
	if (dfr != 0.0) res.push_back(c1.p + diff * Point(rc, -rs));
	return res;
}

/*
点が円の中にいるか
0 => out
1 => on
2 => in*/
int is_in_Circle(const  Point& p, const Circle &cir) {
	ld dis = abs(cir.p - p);
	if (dis > cir.r + eps)return 0;
	else if (dis < cir.r - eps)return 2;
	else return 1;
}
int is_in_Circle(const Circle &cir, const  Point& p) {
	ld dis = abs(cir.p - p);
	if (dis > cir.r + eps)return 0;
	else if (dis < cir.r - eps)return 2;
	else return 1;
}
/*
円lcが円rcの中にいるか
0 => out
1 => on
2 => in*/
int Circle_in_Circle(const Circle &lc, const  Circle&rc) {
	ld dis = abs(lc.p - rc.p);
	if (dis < rc.r - lc.r - eps)return 2;
	else if (dis>rc.r - lc.r + eps)return 0;
	else return 1;
}

// 円と直線の交点
vector<Point> is_lc(const Circle& c, const Line& l) {
	vector<Point> res;
	ld d = dist_lp(l, c.p);
	if (d < c.r + eps) {
		ld len = (d > c.r) ? 0.0 : sqrt(c.r * c.r - d * d); //safety;
		Point nor = (l.a - l.b) / abs(l.a - l.b);
		res.push_back(proj(l, c.p) + len * nor);
		res.push_back(proj(l, c.p) - len * nor);
	}
	return res;
}

// 円と線分の距離
vector<Point> is_sc(const Circle& c, const Line& l) {
	vector<Point> v = is_lc(c, l), res;
	for (Point p : v)
		if (isis_sp(l, p)) res.push_back(p);
	return res;
}

// 円と点の接線
vector<Line> tangent_cp(const Circle& c, const Point& p) {
	vector<Line> ret;
	Point v = c.p - p;
	ld d = abs(v);
	ld l = sqrt(norm(v) - c.r * c.r);
	if (isnan(l)) { return ret; }
	Point v1 = v * Point(l / d, c.r / d);
	Point v2 = v * Point(l / d, -c.r / d);
	ret.push_back(Line(p, p + v1));
	if (l < eps) return ret;
	ret.push_back(Line(p, p + v2));
	return ret;
}

// 円と円の接線
vector<Line> tangent_cc(const Circle& c1, const Circle& c2) {
	vector<Line> ret;
	if (abs(c1.p - c2.p) - (c1.r + c2.r) > -eps) {
		Point center = (c1.p * c2.r + c2.p * c1.r) / (c1.r + c2.r);
		ret = tangent_cp(c1, center);
	}
	if (abs(c1.r - c2.r) > eps) {
		Point out = (-c1.p * c2.r + c2.p * c1.r) / (c1.r - c2.r);
		vector<Line> nret = tangent_cp(c1, out);
		ret.insert(ret.end(), nret.begin(), nret.end());
	}
	else {
		Point v = c2.p - c1.p;
		v /= abs(v);
		Point q1 = c1.p + v * Point(0, 1) * c1.r;
		Point q2 = c1.p + v * Point(0, -1) * c1.r;
		ret.push_back(Line(q1, q1 + v));
		ret.push_back(Line(q2, q2 + v));
	}
	return ret;
}
//二つの円の重なり面積
ld two_Circle_area(const Circle&l, const Circle&r) {
	ld dis = abs(l.p - r.p);
	if (dis > l.r + r.r)return 0;
	else if (dis + r.r < l.r) {
		return r.r*r.r*pi;
	}
	else if (dis + l.r < r.r) {
		return l.r*l.r*pi;
	}
	else {
		ld ans = (l.r)*(l.r)*acos((dis*dis + l.r*l.r - r.r*r.r) / (2 * dis*l.r)) +
			(r.r)*(r.r)*acos((dis*dis + r.r*r.r - l.r*l.r) / (2 * dis*r.r)) -
			sqrt(4 * dis*dis*l.r*l.r - (dis*dis + l.r*l.r - r.r*r.r)*(dis*dis + l.r*l.r - r.r*r.r)) / 2;
		return ans;
	}

}

/* 多角形 */

typedef vector<Point> Polygon;



//多角形(複数の点)の最小包含円をO(N=頂点数)で求めるアルゴリズム
//同一直線上に三つの点がないこと
#include<random>
Circle welzl(vector<Point>ps) {
	struct solver {
		Circle solve(vector<Point>&ps, vector<Point>&rs) {
			if (ps.empty() || rs.size() == 3) {
				if (rs.size() == 1) {
					return Circle(Point(rs[0]), 0);
				}
				else if (rs.size() == 2) {
					return Circle((rs[0] + rs[1]) / 2.0l, abs(rs[1] - rs[0]) / 2);
				}
				else if (rs.size() == 3) {
					vector<Line> ls(3);
					for (int i = 0; i < 3; ++i) {
						ls[i] = Line(rs[i], rs[(i + 1) % 3]);
					}
					Point center = outer_center(rs);
					return Circle(center, abs(center - rs[0]));
				}
				else {
					return Circle(Point(), 0);
				}
			}
			else {

				Point p_ba = ps.back();
				ps.pop_back();
				Circle d = solve(ps, rs);
				ps.push_back(p_ba);
				if (is_in_Circle(d, p_ba)) {
					return d;
				}
				else {
					rs.push_back(p_ba);
					ps.pop_back();
					auto ans = solve(ps, rs);
					ps.push_back(p_ba);
					rs.pop_back();
					return ans;
				}
			}
		}
	}so;
	std::random_device rd;
	std::mt19937 mt(rd());
	shuffle(ps.begin(), ps.end(), mt);
	vector<Point>rs;
	Circle ans = so.solve(ps, rs);
	return ans;
}
// 面積
ld get_area(const Polygon &p) {
	ld res = 0;
	int n = p.size();
	for (int j = 0; j<n; ++j) res += cross(p[j], p[(j + 1) % n]);
	return res / 2;
}

//多角形の回転方向
bool is_counter_clockwise(const Polygon &poly) {
	ld angle = 0;
	int n = poly.size();
	for(int i=0;i<n;++i) {
		Point a = poly[i], b = poly[(i + 1) % n], c = poly[(i + 2) % n];
		angle += arg((c - b) / (b - a));
	}
	return angle > eps;
}

// 円の内外判定
/*0 => out
1 => on
2 => in*/
int is_in_Polygon(const Polygon &poly, const  Point& p) {
	ld angle = 0;
	int n = poly.size();
	for(int i=0;i<n;++i) {
		Point a = poly[i], b = poly[(i + 1) % n];
		if (isis_sp(Line(a, b), p)) return 1;
		angle += arg((b - p) / (a - p));
	}
	return eq(angle, 0) ? 0 : 2;
}
//円の内外判定2　高速
enum { out, on, in };
int convex_contains(const Polygon &P, const Point &p) {
	const int n = P.size();
	Point g = (P[0] + P[n / 3] + P[2 * n / 3]) / 3.0l; // inner-point
	int a = 0, b = n;
	while (a + 1 < b) { // invariant: c is in fan g-P[a]-P[b]
		int c = (a + b) / 2;
		if (cross(P[a] - g, P[c] - g) > 0) { // angle < 180 deg
			if (cross(P[a] - g, p - g) > 0 && cross(P[c] - g, p - g) < 0) b = c;
			else                                                  a = c;
		}
		else {
			if (cross(P[a] - g, p - g) < 0 && cross(P[c] - g, p - g) > 0) a = c;
			else                                                  b = c;
		}
	}
	b %= n;
	if (cross(P[a] - p, P[b] - p) < 0) return 0;
	if (cross(P[a] - p, P[b] - p) > 0) return 2;
	return 1;
}

// 凸包
//点や線を返すことも有り得るので注意
Polygon convex_hull(vector<Point> ps) {
	int n = ps.size();
	int k = 0;
	sort(ps.begin(), ps.end());
	Polygon ch(2 * n);
	for (int i = 0; i < n; ch[k++] = ps[i++])
		while (k >= 2 && ccw(ch[k - 2], ch[k - 1], ps[i]) <= 0) --k;
	for (int i = n - 2, t = k + 1; i >= 0; ch[k++] = ps[i--])
		while (k >= t && ccw(ch[k - 2], ch[k - 1], ps[i]) <= 0) --k;
	ch.resize(k - 1);
	return ch;
}



//凸カット
vector<Polygon> convex_cut(const Polygon &ps, const Line& l) {
	int n = ps.size();
	Polygon q;
	Polygon r;
	for(int i=0;i<n;++i) {
		Point a = ps[i], b = ps[(i + 1) % n];
		Line m = Line(a, b);
		if (ccw(l.a, l.b, a) != -1) q.push_back(a);
		if (ccw(l.a, l.b, a) != 1) r.push_back(a);
		if (ccw(l.a, l.b, a) * ccw(l.a, l.b, b) < 0 && isis_ll(l, m)) {
			q.push_back(is_ll(l, m));
			r.push_back(is_ll(l, m));
		}
	}
	const vector<Polygon>polys{ q,r };
	return polys;
}

Polygon cen(Polygon po) {
	Point cen;
	for (auto p : po) {
		cen += p;
	}
	cen /= po.size();
	for (auto&p : po) {
		p -= cen;
	}
	return po;
}

int main() {
	cout<<setprecision(10)<<fixed;
	cout<<setprecision(10)<<fixed;
	cout<<setprecision(10)<<fixed;
	cout<<setprecision(10)<<fixed;
	cout<<setprecision(10)<<fixed;
	while (true){
		int N;cin>>N;
		if(!N)break;
		Polygon p1,p2;
		for (int i = 0; i < N; ++i) {
			ld x,y; cin>>x>>y;
			p1.emplace_back(x,y);
		}
		for (int i = 0; i < N; ++i) {
			ld x,y; cin>>x>>y;
			p2.emplace_back(x,y);
		}
		p1=cen(p1);
		p2=cen(p2);

		ld ans=1e9;
		for (int i = 0; i < N; ++i) {
			ld theta1=atan2l(p1[0].imag(),p1[0].real());
			ld theta2=atan2l(p2[i].imag(),p2[i].real());

			if (theta2 > theta1) {
				theta1+=2*pi;
			}
			ld sa_theta=theta1-theta2;

			Polygon next_poly(p2);
			for (auto &p : next_poly) {
				Point np;
				np=Point(p.real()*cos(sa_theta)-p.imag()*sin(sa_theta),p.real()*(sin(sa_theta))+p.imag()*cos(sa_theta));
				p=np;
			}

			auto comp = [](const Point&l, const Point&r)-> bool { return abs(l.real() - r.real()) < eps ? abs(l.imag() - r.imag()) < eps ? false : l.imag() < r.imag() : l.real() < r.real(); };
			 std::set <Point, decltype(comp)> aa(comp);

			 for (auto p : next_poly) {
				 aa.emplace(p);
			 }
			 for (auto p : p1) {
				 aa.emplace(p);
			 }

			 if (aa.size() == N) {
				 ans=min(ans,sa_theta);
				 ans=min(ans,2*pi-sa_theta);
			 }


		}
		cout<<ans<<endl;
	}
	return 0;
}
accuracy: 1
time_ms: 490
memory_kb: 3820
final_rank: 20

code_snippet: #include <algorithm>
#include <cassert>
#include <cstring>
#include <iostream>

using namespace std;

#define FOR(i, a, b) for (int i = (a); i < (b); ++i)
#define REP(i, n) FOR(i, 0, n)
#define TRACE(x) cout << #x << " = " << x << endl
#define _ << " _ " <<

typedef long long llint;

const int MAXN = 1000;
const double eps = 1e-7;

inline bool lt(double x, double y) { return x+eps < y; }
inline bool gt(double x, double y) { return lt(y, x); }
inline bool eq(double x, double y) { return !lt(x, y) && !gt(x, y); }

struct Pt {
  double x, y;
  Pt operator - (const Pt &b) { return Pt{x-b.x, y-b.y}; }
};

inline double norm(const Pt &a) {
  return sqrt(a.x*a.x + a.y*a.y);
}

inline double ccw(const Pt &a, const Pt &b, const Pt &c) {
  return a.x * (b.y-c.y) + b.x * (c.y-a.y) + c.x * (a.y-b.y);
}

int n;
Pt P1[MAXN], P2[MAXN], P3[MAXN];
vector<Pt> H1, H2;

double rot1, rot2, ans;

bool load(void) {
  scanf("%d", &n);
  if (n == 0) return false;
  REP (i, n) scanf("%lf%lf", &P1[i].x, &P1[i].y);
  REP (i, n) scanf("%lf%lf", &P2[i].x, &P2[i].y);
  return true;
}

bool cmp(const Pt &a, const Pt &b) {
  if (!eq(a.x, b.x)) return lt(a.x, b.x);
  return lt(a.y, b.y);
}

void convex_hull(Pt *P, int n, vector<Pt> &h) {
  sort(P, P+n, cmp);

  int lsize = 0, usize = 0;
  vector<Pt> lo, up;
  for (int i = 0; i < n; ++i) {
    while (lsize >= 2 && !lt(ccw(lo[lsize-2], lo[lsize-1], P[i]), 0.0)) {
      --lsize;
      lo.pop_back();
    }
    lo.push_back(P[i]);
    ++lsize;
  }

  for (int i = n-1; i >= 0; --i) {
    while (usize >= 2 && !lt(ccw(up[usize-2], up[usize-1], P[i]), 0.0)) {
      --usize;
      up.pop_back();
    }
    up.push_back(P[i]);
    ++usize;
  }

  h.clear();
  for (int i = 0; i < lsize; ++i)
    h.push_back(lo[i]);
  for (int i = 1; i < usize-1; ++i)
    h.push_back(up[i]);
}

void translate(Pt *p, int n, double dx, double dy) {
  REP (i, n) p[i].x += dx, p[i].y += dy;
}

void rotate(Pt *p, int n, double cos_alpha, double sin_alpha) {
  REP (i, n) {
    double nx = p[i].x * cos_alpha - p[i].y * sin_alpha,
           ny = p[i].x * sin_alpha + p[i].y * cos_alpha;
    p[i] = Pt{nx, ny};
  }
}

bool check(int id) {
  for (int sgn: {-1, 1}) {
    memcpy(P3, P2, sizeof P2);
    translate(P3, n, -H2[id].x, -H2[id].y); 
    int nid = (id+1) % (int)H2.size();
    Pt v = H2[nid]-H2[id];
    rotate(P3, n, sgn*v.y/norm(v), sgn*v.x/norm(v));
    sort(P3, P3+n, cmp);

    bool ok = true;
    REP (i, n) {
      if (!eq(P1[i].x, P3[i].x)) { ok = false; break; }
      if (!eq(P1[i].y, P3[i].y)) { ok = false; break; }
    }
    if (ok) {
      rot2 = atan2(sgn*v.y, sgn*v.x);
      double tmp = rot2 - rot1 + 2*M_PI;
      while (gt(tmp, 2*M_PI)) tmp -= 2*M_PI;
      ans = min(ans, min(tmp, 2*M_PI-tmp));
    }
  }
  return false;
}

void solve(void) {
  if (n == 1) {
    printf("0.0\n");
    return;
  }

  ans = 10.0;

  convex_hull(P1, n, H1);
  convex_hull(P2, n, H2);

  translate(P1, n, -H1[0].x, -H1[0].y);
  Pt v = H1[1]-H1[0];
  rotate(P1, n, v.y/norm(v), v.x/norm(v));
  rot1 = atan2(v.y/norm(v), v.x/norm(v));
  sort(P1, P1+n, cmp);

  REP (i, n) check(i);
  printf("%.10lf\n", ans);
}


int main(void) {

  while (load()) solve();

  return 0;
}
accuracy: 1
time_ms: 160
memory_kb: 3496
final_rank: 16

code_snippet: #include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<iostream>
#include<string>
#include<vector>
#include<map>
#include<set>
#include<list>
#include<queue>
#include<deque>
#include<algorithm>
#include<numeric>
#include<utility>
#include<complex>
#include<functional>
 
using namespace std;

/* constant */

const int MAX_N = 1000;

const double DELTA = 1e-4;
const double DELTA2 = 1e-8;
const double PI = acos(-1);
const double PI2 = PI * 2;

/* typedef */

template <typename T>
struct Pt {
  T x, y;

  Pt() {}
  Pt(T _x, T _y) : x(_x), y(_y) {}
  Pt(const Pt& pt) : x(pt.x), y(pt.y) {}

  bool operator==(const Pt pt) const { return x == pt.x && y == pt.y; }
  Pt<T> operator+(const Pt pt) const { return Pt<T>(x + pt.x, y + pt.y); }
  Pt<T> operator-() const { return Pt<T>(-x, -y); }
  Pt<T> operator-(const Pt pt) const { return Pt<T>(x - pt.x, y - pt.y); }
  Pt<T> operator*(T t) const { return Pt<T>(x * t, y * t); }
  Pt<T> operator/(T t) const { return Pt<T>(x / t, y / t); }
  T dot(Pt v) const { return x * v.x + y * v.y; }
  T cross(Pt v) const { return x * v.y - y * v.x; }
  Pt<T> mid(const Pt pt) { return Pt<T>((x + pt.x) / 2, (y + pt.y) / 2); }
  T d2() { return x * x + y * y; }
  double d() { return sqrt(d2()); }

  Pt<T> rot(double th) {
    double c = cos(th), s = sin(th);
    return Pt<T>(c * x - s * y, s * x + c * y);
  }

  bool operator<(const Pt& pt) const {
    return x < pt.x || (x == pt.x && y < pt.y);
  }

  void print(string format) {
    printf(("(" + format + ", " + format + ")\n").c_str(), x, y);
  }
  void print() { print("%.6lf"); }
};

typedef Pt<double> pt;

/* global variables */

int n;
pt pts[2][MAX_N], rpts[MAX_N];

/* subroutines */

bool pt_comp(const pt& pt0, const pt& pt1) {
  double dx = pt0.x - pt1.x, dy = pt0.y - pt1.y;
  return (dx <= -DELTA) || (dx < DELTA && dy <= -DELTA);
}

/* main */

int main() {
  for (;;) {
    cin >> n;
    if (n == 0) break;

    for (int j = 0; j < 2; j++) {
      pt ctr(0.0, 0.0);
      for (int i = 0; i < n; i++) {
	cin >> pts[j][i].x >> pts[j][i].y;
	ctr = ctr + pts[j][i];
      }
      ctr = ctr / n;
      //ctr.print();

      for (int i = 0; i < n; i++)
	pts[j][i] = pts[j][i] - ctr;
    }

    pt *pts0 = pts[0], *pts1 = pts[1];
    double min_th = 10;

    pt& pto = pts0[0];
    double tho = atan2(pto.y, pto.x);
    double d2o = pto.d2();

    for (int i = 0; i < n; i++) {
      pt& pti = pts1[i];
      double d2i = pti.d2();
      if (abs(d2i - d2o) < DELTA2) {
	double thi = atan2(pti.y, pti.x);
	double dth = thi - tho;
	if (dth > PI) dth -= PI2;
	else if (dth < -PI) dth += PI2;

	double adth = abs(dth);
	if (min_th <= adth) continue;
	//cout << dth << endl;

	double cdth = cos(dth), sdth = sin(dth);
	for (int j = 0; j < n; j++) {
	  rpts[j].x = cdth * pts0[j].x - sdth * pts0[j].y;
	  rpts[j].y = sdth * pts0[j].x + cdth * pts0[j].y;
	}
	sort(rpts, rpts + n, pt_comp);

	bool found = true;
	for (int j = 0; j < n; j++)
	  if (! binary_search(rpts, rpts + n, pts1[j], pt_comp)) {
	    found = false;
	    break;
	  }

	if (found) min_th = adth;
      }
    }

    printf("%.10lf\n", min_th);
  }

  return 0;
}
accuracy: 1
time_ms: 20
memory_kb: 1372
final_rank: 3

code_snippet: #include <bits/stdc++.h>
#define REP(i,n) for(int i=0; i<(int)(n); ++i)
using namespace std;
typedef long long LL;
#define curr(P, i) P[i]
#define next(P, i) P[(i+1)%P.size()]
#define diff(P, i) (next(P, i) - curr(P, i))
typedef double number;
typedef complex<double> Point;
const double EPS = 1e-5;
typedef Point P;
typedef vector<Point> Polygon;
double dot(P a, P b){return real(conj(a) * b);}
double cross(P a, P b){return imag(conj(a) * b);}
double angle(P a, P b){return arg(conj(a) * b);}
P rotate(P a, double b, P c = P()){return (a - c) * polar(1.0, b) + c;}
int ccw(P a, P b, P c) {
    b -= a; c -= a;
    if (cross(b, c) > +EPS)   return +1; // 反時計回り
    if (cross(b, c) < -EPS)   return -1; // 時計回り
    if (dot(b, c) < 0)     return +2; // c--a--b の順番で一直線上
    if (norm(b) < norm(c)) return -2; // a--b--c の順番で一直線上
    return 0;                         // 点が線分ab上にある
}
int sign(double x) {
    return (x > EPS) - (x < -EPS);
}
int comp(double x, double y) {
    return sign(x - y);
}
namespace std{
    bool operator < (const P& a, const P& b) {
        return a.real() != b.real() ? a.real() < b.real() : a.imag() < b.imag();
        return comp(a.real(), b.real()) ? comp(a.real(), b.real()) < 0 : comp(a.imag(), b.imag()) < 0;
    }
};
bool near(Point a, Point b) {
    return comp(a.real(), b.real()) == 0 && comp(a.imag(), b.imag()) == 0;
}
bool equal(Polygon p, Polygon q) {
    sort(p.begin(), p.end());
    sort(q.begin(), q.end());
    REP(i, p.size()) {
        if(!near(p[i], q[i])) return false;
    }
    return true;
}
Polygon convex_hull(vector<P> ps, vector<int>& res) {
    int n = ps.size(), k = 0;
    sort(ps.begin(), ps.end(),[](const P&a, const P&b){
            return real(a) != real(b) ? real(a) < real(b) : imag(a) < imag(b);
            });

    vector<P> ch(2*n);
    res.resize(2*n);
    for (int i = 0; i < n;
            res[k] = i, ch[k++] = ps[i++]){ // lower-hull
        while (k >= 2 && ccw(ch[k-2], ch[k-1], ps[i]) <= 0) --k;
    }
    for (int i = n-2, t = k+1; i >= 0;
            res[k] = i, ch[k++] = ps[i--]){ // upper-hull
        while (k >= t && ccw(ch[k-2], ch[k-1], ps[i]) <= 0) --k;
    }
    ch.resize(k-1);
    res.resize(k-1);
    return ch;
}
pair<int, int> convex_diameter(const Polygon &pt) {
  const int n = pt.size();
  int is = 0, js = 0;
  for (int i = 1; i < n; ++i) {
    if (imag(pt[i]) > imag(pt[is])) is = i;
    if (imag(pt[i]) < imag(pt[js])) js = i;
  }
  number maxd = norm(pt[is]-pt[js]);

  int i, maxi, j, maxj;
  i = maxi = is;
  j = maxj = js;
  do {
    if (cross(diff(pt,i), diff(pt,j)) >= 0) j = (j+1) % n;
    else i = (i+1) % n;
    if (norm(pt[i]-pt[j]) > maxd) {
      maxd = norm(pt[i]-pt[j]);
      maxi = i; maxj = j;
    }
  } while (i != is || j != js);
  return make_pair(maxi, maxj); /* farthest pair is (maxi, maxj). */
}

int main(){
    int n;
    while(cin >> n && n > 0) {
        Polygon p(n), q(n);
        REP(i, n) {
            double x, y;
            cin >> x >> y;
            p[i] = {x, y};
        }
        REP(i, n) {
            double x, y;
            cin >> x >> y;
            q[i] = {x, y};
        }
        if(n == 1) {
            printf("%.10f\n", 0.0);
            continue;
        }
        vector<int> idx;
        auto pc = convex_hull(p, idx);
        auto max_p = convex_diameter(pc);
        int max_i = idx[max_p.first];
        int max_j = idx[max_p.second];
        double max_len = abs(p[max_i] - p[max_j]);
        double ans = 1e64;
        REP(i, n) REP(j, n) if(i != j) {
            double len = abs(q[i] - q[j]);
            if(comp(len, max_len) != 0) continue;
            auto qt = q;
            P dif = p[max_i] - qt[i];
            REP(k, qt.size()) {
                qt[k] += dif;
            }
            assert(near(p[max_i], qt[i]));
            // double th = angle(p[max_j] - p[max_i], qt[j] - qt[i]);
            // REP(k, qt.size()) {
            //     qt[k] = rotate(qt[k], -th, qt[i]);
            // }
            double th = angle(qt[j] - qt[i], p[max_j] - p[max_i]);
            REP(k, qt.size()) {
                qt[k] = rotate(qt[k], th, qt[i]);
            }
            assert(near(p[max_i], qt[i]));
            assert(near(p[max_j], qt[j]));
            if(!equal(p, qt)) continue;
            th = abs(th);
            ans = min(ans, th);
        }
        printf("%.10f\n", ans);
    }
    return 0;
}
accuracy: 1
time_ms: 100
memory_kb: 1460
final_rank: 9

code_snippet: #include<bits/stdc++.h>
  
#define REP(i,s,n) for(int i=s;i<n;i++)
#define rep(i,n) REP(i,0,n)
#define EPS (1e-8)
#define equals(a,b) (fabs((a)-(b))<EPS)
  
using namespace std;
  
class Point{
public:
  double x,y;
  
  Point(double x = 0,double y = 0): x(x),y(y){}
  Point operator + (Point p){return Point(x+p.x,y+p.y);}
  Point operator - (Point p){return Point(x-p.x,y-p.y);}
  Point operator * (double a){return Point(a*x,a*y);}
  Point operator / (double a){return Point(x/a,y/a);}
  bool operator < (const Point& p) const{ return !equals(x,p.x)?x<p.x:(!equals(y,p.y)&&y<p.y); }
  bool operator == (const Point& p)const{ return fabs(x-p.x) < EPS && fabs(y-p.y) < EPS; }
  
};
  
Point rotate(Point a,double rad){ return Point(cos(rad)*a.x - sin(rad)*a.y,sin(rad)*a.x + cos(rad)*a.y); }
  
const double DINF = 1e20;
int n;
Point ps[2][1010],tmp[1010];
  
inline double getDist(Point p){ return sqrt(p.x*p.x+p.y*p.y); }
inline bool comp_arg(const double &a,const double &b) { return !equals(a,b) && a < b; }
  
void compute(){
  Point grv[2] = {Point(),Point()};
  rep(i,2) rep(j,n) grv[i] = grv[i] + ps[i][j];
  rep(i,2) grv[i] = grv[i] / (double)n;
  rep(i,2) rep(j,n) ps[i][j] = ps[i][j] - grv[i];
  sort(ps[0],ps[0]+n);
  
  vector<double> arg_buf;
  rep(i,n) {
    double dist[2] = { getDist(ps[0][0]), getDist(ps[1][i]) };
    if( !equals(dist[0],dist[1]) ) continue;
    double arg = atan2(ps[0][0].y,ps[0][0].x) - atan2(ps[1][i].y,ps[1][i].x);
    while( arg < 0 ) arg += 2*M_PI;
    arg_buf.push_back(arg);
  }
  sort(arg_buf.begin(),arg_buf.end(),comp_arg);
  arg_buf.erase(unique(arg_buf.begin(),arg_buf.end()),arg_buf.end());

  double mini = DINF;  
  rep(i,(int)arg_buf.size()){
    double arg = arg_buf[i];
    rep(j,n) tmp[j] = rotate(ps[1][j],arg);
    sort(tmp,tmp+n);
    bool failed = false;
    rep(j,n) if( !( tmp[j] == ps[0][j] ) ) { failed = true; break; }
    if( !failed ) mini = min(mini,min(arg,2*M_PI-arg));
  }
  printf("%.11lf\n",mini);
}
  
int main(){
  while( cin >> n, n ){
    rep(i,2) rep(j,n) cin >> ps[i][j].x >> ps[i][j].y;
    compute();
  }
  return 0;
}
accuracy: 1
time_ms: 40
memory_kb: 1408
final_rank: 8

code_snippet: #include<bits/stdc++.h>
  
#define REP(i,s,n) for(int i=s;i<n;i++)
#define rep(i,n) REP(i,0,n)
#define EPS (1e-8)
#define equals(a,b) (fabs((a)-(b))<EPS)
  
using namespace std;
  
class Point{
public:
  double x,y;
  
  Point(double x = 0,double y = 0): x(x),y(y){}
  Point operator + (Point p){return Point(x+p.x,y+p.y);}
  Point operator - (Point p){return Point(x-p.x,y-p.y);}
  Point operator * (double a){return Point(a*x,a*y);}
  Point operator / (double a){return Point(x/a,y/a);}
  bool operator < (const Point& p) const{ return !equals(x,p.x)?x<p.x:(!equals(y,p.y)&&y<p.y); }
  bool operator == (const Point& p)const{ return fabs(x-p.x) < EPS && fabs(y-p.y) < EPS; }
  
};
  
Point rotate(Point a,double rad){ return Point(cos(rad)*a.x - sin(rad)*a.y,sin(rad)*a.x + cos(rad)*a.y); }
  
const double DINF = 1e20;
int n;
Point ps[2][1010],tmp[1010];
  
inline double getDist(Point p){ return sqrt(p.x*p.x+p.y*p.y); }
  
bool comp_arg(const double &a,const double &b) { return !equals(fabs(a),fabs(b)) && fabs(a) < fabs(b); }
  
void compute(){
  Point grv[2] = {Point(),Point()};
  rep(i,2) rep(j,n) grv[i] = grv[i] + ps[i][j];
  rep(i,2) grv[i] = grv[i] / (double)n;
  rep(i,2) rep(j,n) ps[i][j] = ps[i][j] - grv[i];
  sort(ps[0],ps[0]+n);
  sort(ps[1],ps[1]+n);
  
  vector<double> arg_buf;
  rep(i,min(10,n)) rep(j,n) {
    double dist[2] = { getDist(ps[0][i]), getDist(ps[1][j]) };
    if( !equals(dist[0],dist[1]) ) continue;
    arg_buf.push_back( atan2(ps[0][i].y,ps[0][i].x) - atan2(ps[1][j].y,ps[1][j].x) );
  }
  
  sort(arg_buf.begin(),arg_buf.end(),comp_arg);
  arg_buf.erase(unique(arg_buf.begin(),arg_buf.end()),arg_buf.end());
  
  rep(i,(int)arg_buf.size()){
    double arg = arg_buf[i];
    rep(j,n) tmp[j] = rotate(ps[1][j],arg);
    sort(tmp,tmp+n);
    bool failed = false;
    rep(j,n) if( !( tmp[j] == ps[0][j] ) ) { failed = true; break; }
    if( !failed ) { printf("%.10lf\n",fabs(arg)); break; }
  }
  
}
  
int main(){
  while( cin >> n, n ){
    rep(i,2) rep(j,n) cin >> ps[i][j].x >> ps[i][j].y;
    compute();
  }
  return 0;
}
accuracy: 1
time_ms: 20
memory_kb: 1512
final_rank: 6

code_snippet: #include<bits/stdc++.h>
 
#define REP(i,s,n) for(int i=s;i<n;i++)
#define rep(i,n) REP(i,0,n)
#define EPS (1e-8)
#define equals(a,b) (fabs((a)-(b))<EPS)
 
using namespace std;
 
class Point{
public:
  double x,y;
 
  Point(double x = 0,double y = 0): x(x),y(y){}
  Point operator + (Point p){return Point(x+p.x,y+p.y);}
  Point operator - (Point p){return Point(x-p.x,y-p.y);}
  Point operator * (double a){return Point(a*x,a*y);}
  Point operator / (double a){return Point(x/a,y/a);}
  bool operator < (const Point& p) const{ return !equals(x,p.x)?x<p.x:(!equals(y,p.y)&&y<p.y); }
  bool operator == (const Point& p)const{ return fabs(x-p.x) < EPS && fabs(y-p.y) < EPS; }
 
};
 
Point rotate(Point a,double rad){ return Point(cos(rad)*a.x - sin(rad)*a.y,sin(rad)*a.x + cos(rad)*a.y); }
 
const double DINF = 1e20;
int n;
Point ps[2][1010],tmp[1010];
 
inline double getDist(Point p){ return sqrt(p.x*p.x+p.y*p.y); }
 
bool comp_arg(const double &a,const double &b) { return !equals(fabs(a),fabs(b)) && fabs(a) < fabs(b); }
 
void compute(){
  Point grv[2] = {Point(),Point()};
  rep(i,2) rep(j,n) grv[i] = grv[i] + ps[i][j];
  rep(i,2) grv[i] = grv[i] / (double)n;
  rep(i,2) rep(j,n) ps[i][j] = ps[i][j] - grv[i];
  sort(ps[0],ps[0]+n);
 
  vector<double> arg_buf;
  rep(i,min(10,n)) rep(j,n) {
    double dist[2] = { getDist(ps[0][i]), getDist(ps[1][j]) };
    if( !equals(dist[0],dist[1]) ) continue;
    arg_buf.push_back( atan2(ps[0][i].y,ps[0][i].x) - atan2(ps[1][j].y,ps[1][j].x) );
  }
 
  sort(arg_buf.begin(),arg_buf.end(),comp_arg);
  arg_buf.erase(unique(arg_buf.begin(),arg_buf.end()),arg_buf.end());
 
  rep(i,(int)arg_buf.size()){
    double arg = arg_buf[i];
    rep(j,n) tmp[j] = rotate(ps[1][j],arg);
    sort(tmp,tmp+n);
    bool failed = false;
    rep(j,n) if( !( tmp[j] == ps[0][j] ) ) { failed = true; break; }
    if( !failed ) { printf("%.10lf\n",fabs(arg)); break; }
  }
 
}
 
int main(){
  while( cin >> n, n ){
    rep(i,2) rep(j,n) cin >> ps[i][j].x >> ps[i][j].y;
    compute();
  }
  return 0;
}
accuracy: 1
time_ms: 20
memory_kb: 1512
final_rank: 6

code_snippet: #include<bits/stdc++.h>
 
#define REP(i,s,n) for(int i=s;i<n;i++)
#define rep(i,n) REP(i,0,n)
#define EPS (1e-8)
#define equals(a,b) (fabs((a)-(b))<EPS)
 
using namespace std;
 
class Point{
public:
  double x,y;
 
  Point(double x = 0,double y = 0): x(x),y(y){}
  Point operator + (Point p){return Point(x+p.x,y+p.y);}
  Point operator - (Point p){return Point(x-p.x,y-p.y);}
  Point operator * (double a){return Point(a*x,a*y);}
  Point operator / (double a){return Point(x/a,y/a);}
  bool operator < (const Point& p) const{ return !equals(x,p.x)?x<p.x:(!equals(y,p.y)&&y<p.y); }
  bool operator == (const Point& p)const{ return fabs(x-p.x) < EPS && fabs(y-p.y) < EPS; }
 
};
 
Point rotate(Point a,double rad){ return Point(cos(rad)*a.x - sin(rad)*a.y,sin(rad)*a.x + cos(rad)*a.y); }
 
const double DINF = 1e20;
int n;
Point ps[2][1010],tmp[1010];
 
inline double getDist(Point p){ return sqrt(p.x*p.x+p.y*p.y); }
 
bool comp_arg(const double &a,const double &b) { return !equals(fabs(a),fabs(b)) && fabs(a) < fabs(b); }
 
void compute(){
  Point grv[2] = {Point(),Point()};
  rep(i,2) rep(j,n) grv[i] = grv[i] + ps[i][j];
  rep(i,2) grv[i] = grv[i] / (double)n;
  rep(i,2) rep(j,n) ps[i][j] = ps[i][j] - grv[i];
  sort(ps[0],ps[0]+n);
  sort(ps[1],ps[1]+n);
 
  vector<double> arg_buf;
  rep(i,min(7,n)) rep(j,n) {
    double dist[2] = { getDist(ps[0][i]), getDist(ps[1][j]) };
    if( !equals(dist[0],dist[1]) ) continue;
    arg_buf.push_back( atan2(ps[0][i].y,ps[0][i].x) - atan2(ps[1][j].y,ps[1][j].x) );
  }
 
  sort(arg_buf.begin(),arg_buf.end(),comp_arg);
  arg_buf.erase(unique(arg_buf.begin(),arg_buf.end()),arg_buf.end());
 
  rep(i,(int)arg_buf.size()){
    double arg = arg_buf[i];
    rep(j,n) tmp[j] = rotate(ps[1][j],arg);
    sort(tmp,tmp+n);
    bool failed = false;
    rep(j,n) if( !( tmp[j] == ps[0][j] ) ) { failed = true; break; }
    if( !failed ) { printf("%.10lf\n",fabs(arg)); break; }
  }
 
}
 
int main(){
  while( cin >> n, n ){
    rep(i,2) rep(j,n) cin >> ps[i][j].x >> ps[i][j].y;
    compute();
  }
  return 0;
}
accuracy: 1
time_ms: 20
memory_kb: 1468
final_rank: 5

code_snippet: #include<bits/stdc++.h>
 
#define REP(i,s,n) for(int i=s;i<n;i++)
#define rep(i,n) REP(i,0,n)
#define EPS (1e-8)
#define equals(a,b) (fabs((a)-(b))<EPS)
 
using namespace std;
 
class Point{
public:
  double x,y;
 
  Point(double x = 0,double y = 0): x(x),y(y){}
  Point operator + (Point p){return Point(x+p.x,y+p.y);}
  Point operator - (Point p){return Point(x-p.x,y-p.y);}
  Point operator * (double a){return Point(a*x,a*y);}
  Point operator / (double a){return Point(x/a,y/a);}
  bool operator < (const Point& p) const{ return !equals(x,p.x)?x<p.x:(!equals(y,p.y)&&y<p.y); }
  bool operator == (const Point& p)const{ return fabs(x-p.x) < EPS && fabs(y-p.y) < EPS; }
 
};
 
Point rotate(Point a,double rad){ return Point(cos(rad)*a.x - sin(rad)*a.y,sin(rad)*a.x + cos(rad)*a.y); }
 
const double DINF = 1e20;
int n;
Point ps[2][1010],tmp[1010];
 
inline double getDist(Point p){ return sqrt(p.x*p.x+p.y*p.y); }
 
bool comp_arg(const double &a,const double &b) { return !equals(fabs(a),fabs(b)) && fabs(a) < fabs(b); }
 
void compute(){
  Point grv[2] = {Point(),Point()};
  rep(i,2) rep(j,n) grv[i] = grv[i] + ps[i][j];
  rep(i,2) grv[i] = grv[i] / (double)n;
  rep(i,2) rep(j,n) ps[i][j] = ps[i][j] - grv[i];
  sort(ps[0],ps[0]+n);
  sort(ps[1],ps[1]+n);
 
  vector<double> arg_buf;
  rep(i,min(10,n)) rep(j,n) {
    double dist[2] = { getDist(ps[0][i]), getDist(ps[1][j]) };
    if( !equals(dist[0],dist[1]) ) continue;
    arg_buf.push_back( atan2(ps[0][i].y,ps[0][i].x) - atan2(ps[1][j].y,ps[1][j].x) );
  }
 
  sort(arg_buf.begin(),arg_buf.end(),comp_arg);
  arg_buf.erase(unique(arg_buf.begin(),arg_buf.end()),arg_buf.end());
 
  rep(i,(int)arg_buf.size()){
    double arg = arg_buf[i];
    rep(j,n) tmp[j] = rotate(ps[1][j],arg);
    sort(tmp,tmp+n);
    bool failed = false;
    rep(j,n) if( !( tmp[j] == ps[0][j] ) ) { failed = true; break; }
    if( !failed ) { printf("%.10lf\n",fabs(arg)); break; }
  }
 
}
 
int main(){
  while( cin >> n, n ){
    rep(i,2) rep(j,n) cin >> ps[i][j].x >> ps[i][j].y;
    compute();
  }
  return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 1512
final_rank: 4

code_snippet: #include<bits/stdc++.h>

#define REP(i,s,n) for(int i=s;i<n;i++)
#define rep(i,n) REP(i,0,n)
#define EPS (1e-8)
#define equals(a,b) (fabs((a)-(b))<EPS)

using namespace std;

class Point{
public:
  double x,y;

  Point(double x = 0,double y = 0): x(x),y(y){}
  Point operator + (Point p){return Point(x+p.x,y+p.y);}
  Point operator - (Point p){return Point(x-p.x,y-p.y);}
  Point operator * (double a){return Point(a*x,a*y);}
  Point operator / (double a){return Point(x/a,y/a);}
  bool operator < (const Point& p) const{ return !equals(x,p.x)?x<p.x:(!equals(y,p.y)&&y<p.y); }
  bool operator == (const Point& p)const{ return fabs(x-p.x) < EPS && fabs(y-p.y) < EPS; }

};

Point rotate(Point a,double rad){ return Point(cos(rad)*a.x - sin(rad)*a.y,sin(rad)*a.x + cos(rad)*a.y); }

const double DINF = 1e20;
int n;
Point ps[2][1010],tmp[1010];

inline double getDist(Point p){ return sqrt(p.x*p.x+p.y*p.y); }

bool comp_arg(const double &a,const double &b) { return !equals(fabs(a),fabs(b)) && fabs(a) < fabs(b); }

void compute(){
  Point grv[2] = {Point(),Point()};
  rep(i,2) rep(j,n) grv[i] = grv[i] + ps[i][j];
  rep(i,2) grv[i] = grv[i] / (double)n;
  rep(i,2) rep(j,n) ps[i][j] = ps[i][j] - grv[i];
  sort(ps[0],ps[0]+n);
  sort(ps[1],ps[1]+n);

  vector<double> arg_buf;
  rep(i,n) rep(j,n) {
    double dist[2] = { getDist(ps[0][i]), getDist(ps[1][j]) };
    if( !equals(dist[0],dist[1]) ) continue;
    double arg = atan2(ps[0][i].y,ps[0][i].x) - atan2(ps[1][j].y,ps[1][j].x);
    arg_buf.push_back(arg);
  }

  sort(arg_buf.begin(),arg_buf.end(),comp_arg);
  arg_buf.erase(unique(arg_buf.begin(),arg_buf.end()),arg_buf.end());

  rep(i,(int)arg_buf.size()){
    double arg = arg_buf[i];
    rep(j,n) tmp[j] = rotate(ps[1][j],arg);
    sort(tmp,tmp+n);
    bool failed = false;
    rep(j,n) if( !( tmp[j] == ps[0][j] ) ) { failed = true; break; }
    if( !failed ) { printf("%.11lf\n",fabs(arg)); break; }
  }

}

int main(){
  while( cin >> n, n ){
    rep(i,2) rep(j,n) cin >> ps[i][j].x >> ps[i][j].y;
    compute();
  }
  return 0;
}
accuracy: 1
time_ms: 70
memory_kb: 3356
final_rank: 12

code_snippet: #include<bits/stdc++.h>

#define REP(i,s,n) for(int i=s;i<n;i++)
#define rep(i,n) REP(i,0,n)
#define EPS (1e-8)
#define equals(a,b) (fabs((a)-(b))<EPS)

using namespace std;

class Point{
public:
  double x,y;

  Point(double x = 0,double y = 0): x(x),y(y){}

  Point operator + (Point p){return Point(x+p.x,y+p.y);}
  Point operator - (Point p){return Point(x-p.x,y-p.y);}
  Point operator * (double a){return Point(a*x,a*y);}
  Point operator / (double a){return Point(x/a,y/a);}
  Point operator * (Point a){ return Point(x * a.x - y * a.y, x * a.y + y * a.x); }

  bool operator < (const Point& p) const{ return !equals(x,p.x)?x<p.x:(!equals(y,p.y)&&y<p.y); }

  bool operator == (const Point& p)const{ return fabs(x-p.x) < EPS && fabs(y-p.y) < EPS; }

};

//rad は角度をラジアンで持たせること
Point rotate(Point a,double rad){ return Point(cos(rad)*a.x - sin(rad)*a.y,sin(rad)*a.x + cos(rad)*a.y); }

const double DINF = 1e20;
int n;
Point ps[2][1010],tmp[1010];

inline double getDist(Point p){ return sqrt(p.x*p.x+p.y*p.y); }

bool comp_arg(const double &a,const double &b) { return !equals(fabs(a),fabs(b)) && fabs(a) < fabs(b); }

void compute(){
  Point grv[2] = {Point(),Point()};
  rep(i,2) rep(j,n) grv[i] = grv[i] + ps[i][j];
  rep(i,2) grv[i] = grv[i] / (double)n;
  rep(i,2) rep(j,n) ps[i][j] = ps[i][j] - grv[i];
  sort(ps[0],ps[0]+n);
  sort(ps[1],ps[1]+n);

  vector<double> arg_buf;
  rep(i,n) rep(j,n) {
    double dist[2] = { getDist(ps[0][i]), getDist(ps[1][j]) };
    if( !equals(dist[0],dist[1]) ) continue;
    double arg = atan2(ps[0][i].y,ps[0][i].x) - atan2(ps[1][j].y,ps[1][j].x);
    arg_buf.push_back(arg);
  }

  sort(arg_buf.begin(),arg_buf.end(),comp_arg);
  arg_buf.erase(unique(arg_buf.begin(),arg_buf.end()),arg_buf.end());

  rep(i,(int)arg_buf.size()){
    double arg = arg_buf[i];
    rep(j,n) tmp[j] = rotate(ps[1][j],arg);
    sort(tmp,tmp+n);
    bool failed = false;
    rep(j,n) if( !( tmp[j] == ps[0][j] ) ) { failed = true; break; }
    if( !failed ) { printf("%.11lf\n",fabs(arg)); break; }
  }

}

int main(){
  while( cin >> n, n ){
    rep(i,2) rep(j,n) cin >> ps[i][j].x >> ps[i][j].y;
    compute();
  }
  return 0;
}
accuracy: 1
time_ms: 70
memory_kb: 3360
final_rank: 13

code_snippet: #include <algorithm>
#include <bitset>
#include <cmath>
#include <complex>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <vector>

#define repi(i,a,b) for(int i = (a); i < (b); i++)
#define rep(i,a) repi(i,0,a)
#define repd(i,a,b) for(int i = (a) ; i >= (b); i--)
#define repit(i,a) for(__typeof((a).begin()) i = (a).begin(); i!= (a).end(); i++)
#define all(u) (u).begin(),(u).end()
#define rall(u) (u).rbegin(),(u).rend()
#define UNIQUE(u) (u).erase(unique(all(u)),(u).end)

#define pb push_back
#define mp make_pair
#define INF 1e9
#define EPS 1e-6
#define PI acos(-1.0)

using namespace std;

typedef long long ll;
typedef vector<int> vi;
typedef complex<double> P;
typedef vector<P> G;
int n;

namespace std{
    bool operator<(const P &a, const P &b) {
	return abs(real(a)-real(b)) > EPS ? real(a) < real(b): imag(a) < imag(b);
    }
}

struct cmp
{
    bool operator ()(const double &a, const double &b) {
	return a + EPS < b;
    }
};

P rotate(const P &a, double th) { return a*polar(1.0, th); }
double angle(const P &a, const P &b) { return arg(conj(a)*b); }

P centerG(const G &g) {
    P p = P(0, 0);
    rep(i, n) p += g[i];
    p /= n;
    return p;
}

int main(){
    while(cin >> n, n) {
	G g1(n), g2(n);
	rep(i, n) cin >> g1[i].real() >> g1[i].imag();
	rep(i, n) cin >> g2[i].real() >> g2[i].imag();
	P c1 = centerG(g1), c2 = centerG(g2);
	rep(i, n) {
	    g1[i] -= c1;
	    g2[i] -= c2;
	}
	//cout <<"c " << c1 << " " << c2 << endl;
	G tg = g2;
	double ans = INF;
	sort(all(g1));
	rep(i, n) {
	    g2 = tg;
	    double th = angle(g2[i], g1[0]); 
	    rep(j, n) g2[j] = rotate(g2[j], th);
	    bool flag = true;
	    
	    sort(all(g2));
	    rep(j, n) if(abs(g1[j] - g2[j]) > EPS) flag = false;
	    
	    //cout << "a "<< i << endl;
	    //rep(j, n) cout << g1[j] << g2[j] << endl;
	    
	    if(flag) {
		if(th < 0) th = -th;
		if(th > PI) th = 2*PI - th;
		ans = min(ans, th);
	    }
	}
	printf("%.11f\n", ans);
    }
    return 0;
}
accuracy: 1
time_ms: 190
memory_kb: 1396
final_rank: 10

code_snippet: #include<set>
#include<cmath>
#include<cstdio>
#include<vector>
#include<algorithm>

#define rep(i,n) for(int i=0;i<(n);i++)

using namespace std;

const double EPS=1e-7; // EPS=1e-8 だと誤差で間違う
const double INF=1e77;
const double PI=acos(-1);

struct point{
	double x,y;
	point():x(0),y(0){}
	point(double x,double y):x(x),y(y){}
	point &operator+=(const point &a){ x+=a.x; y+=a.y; return *this; }
	point &operator-=(const point &a){ x-=a.x; y-=a.y; return *this; }
	point &operator/=(double c){ x/=c; y/=c; return *this; }
	point operator+(const point &a)const{ return point(x+a.x,y+a.y); }
	point operator-(const point &a)const{ return point(x-a.x,y-a.y); }
	bool operator< (const point &a)const{ return x+EPS<a.x || abs(x-a.x)<EPS && y+EPS<a.y; }
};

double cross(const point &a,const point &b){ return a.x*b.y-a.y*b.x; }

double abs(const point &a){ return sqrt(a.x*a.x+a.y*a.y); }

double arg(const point &a){ double t=atan2(a.y,a.x); return t<0?t+2*PI:t; }

point rot(const point &a,double theta){ return point(a.x*cos(theta)-a.y*sin(theta),a.x*sin(theta)+a.y*cos(theta)); }

typedef vector<point> polygon;

enum{CCW=1,CW=-1,ON=0};
int ccw(const point &a,const point &b,const point &c){
	double rdir=cross(b-a,c-a);
	if(rdir> EPS) return CCW;
	if(rdir<-EPS) return CW;
	return ON;
}

polygon convex_hull(vector<point> &P){
	int n=P.size();
	polygon CH;
	if(n<=1){
		CH.insert(CH.end(),P.begin(),P.end());
		return CH;
	}
	sort(P.begin(),P.end());

	rep(_,2){
		int m=0;
		vector<point> half(n);
		rep(i,n){
			half[m++]=P[i];
			while(m>=3 && ccw(half[m-3],half[m-2],half[m-1])==CW){
				half[m-2]=half[m-1];
				m--;
			}
		}
		CH.insert(CH.end(),half.begin(),half.begin()+m-1);
		reverse(P.begin(),P.end());
	}

	return CH;
}

int main(){
	for(int n;scanf("%d",&n),n;){
		vector<point> P(n),Q(n);
		rep(i,n) scanf("%lf%lf",&P[i].x,&P[i].y);
		rep(i,n) scanf("%lf%lf",&Q[i].x,&Q[i].y);

		if(n==1){
			puts("0");
			continue;
		}

		polygon F=convex_hull(P);
		polygon G=convex_hull(Q);

		set<point> S(Q.begin(),Q.end());

		double ans=INF;
		rep(i,G.size()){
			point v=G[i]-F[0];
			double theta=arg(G[(i+1)%G.size()]-G[i])-arg(F[1]-F[0]);

			bool ok=true;
			rep(j,n){
				if(S.count(rot(P[j]-F[0],theta)+F[0]+v)==0){
					ok=false;
					break;
				}
			}
			if(ok){
				theta=abs(theta);
				while(theta>2*PI) theta-=2*PI;
				ans=min(ans,theta);
				ans=min(ans,2*PI-theta);
			}
		}
		printf("%.9f\n",ans);
	}

	return 0;
}
accuracy: 1
time_ms: 30
memory_kb: 1296
final_rank: 1

code_snippet: #include<set>
#include<cmath>
#include<cstdio>
#include<vector>
#include<algorithm>

#define rep(i,n) for(int i=0;i<(n);i++)

using namespace std;

const double EPS=1e-7; // EPS=1e-8 だと誤差で間違う
const double INF=1e77;
const double PI=acos(-1);

struct point{
	double x,y;
	point():x(0),y(0){}
	point(double x,double y):x(x),y(y){}
	point &operator+=(const point &a){ x+=a.x; y+=a.y; return *this; }
	point &operator-=(const point &a){ x-=a.x; y-=a.y; return *this; }
	point &operator/=(double c){ x/=c; y/=c; return *this; }
	point operator+(const point &a)const{ return point(x+a.x,y+a.y); }
	point operator-(const point &a)const{ return point(x-a.x,y-a.y); }
	bool operator< (const point &a)const{ return x+EPS<a.x || abs(x-a.x)<EPS && y+EPS<a.y; }
};

double cross(const point &a,const point &b){ return a.x*b.y-a.y*b.x; }

double abs(const point &a){ return sqrt(a.x*a.x+a.y*a.y); }

double arg(const point &a){ double t=atan2(a.y,a.x); return t<0?t+2*PI:t; }

point rot(const point &a,double theta){ return point(a.x*cos(theta)-a.y*sin(theta),a.x*sin(theta)+a.y*cos(theta)); }

typedef vector<point> polygon;

enum{CCW=1,CW=-1,ON=0};
int ccw(const point &a,const point &b,const point &c){
	double rdir=cross(b-a,c-a);
	if(rdir> EPS) return CCW;
	if(rdir<-EPS) return CW;
	return ON;
}

polygon convex_hull(vector<point> &P){
	int n=P.size();
	polygon CH;
	if(n<=1){
		CH.insert(CH.end(),P.begin(),P.end());
		return CH;
	}
	sort(P.begin(),P.end());

	rep(_,2){
		int m=0;
		vector<point> half(n);
		rep(i,n){
			half[m++]=P[i];
			while(m>=3 && ccw(half[m-3],half[m-2],half[m-1])==CW){
				half[m-2]=half[m-1];
				m--;
			}
		}
		CH.insert(CH.end(),half.begin(),half.begin()+m-1);
		reverse(P.begin(),P.end());
	}

	return CH;
}

int main(){
	for(int n;scanf("%d",&n),n;){
		vector<point> P(n),Q(n);
		rep(i,n) scanf("%lf%lf",&P[i].x,&P[i].y);
		rep(i,n) scanf("%lf%lf",&Q[i].x,&Q[i].y);

		if(n==1){
			puts("0");
			continue;
		}

		polygon F=convex_hull(P);
		polygon G=convex_hull(Q);

		set<point> S(Q.begin(),Q.end());

		double ans=INF;
		rep(_,2){
			rep(i,G.size()){
				point v=G[i]-F[0];
				double theta=arg(G[(i+1)%G.size()]-G[i])-arg(F[1]-F[0]);

				bool ok=true;
				rep(j,n){
					if(S.count(rot(P[j]-F[0],theta)+F[0]+v)==0){
						ok=false;
						break;
					}
				}
				if(ok){
					theta=abs(theta);
					while(theta>2*PI) theta-=2*PI;
					ans=min(ans,theta);
					ans=min(ans,2*PI-theta);
				}
			}
			reverse(G.begin(),G.end());
		}
		printf("%.9f\n",ans);
	}

	return 0;
}
accuracy: 1
time_ms: 30
memory_kb: 1296
final_rank: 1