Problem:
Idealistic Canister
The Ideally Compact Packaging Canisters (ICPC) corporation is a
package manufacturer specialized in canisters (cylindrical containers),
designing and manufacturing canisters satisfying clients' demands.
The corporation has taken an order of a canister to pack two different products together.
Both products have shapes of convex polygonal prisms with the same height.
The inside of the canister should be precisely a cylinder whose height is equal to the height of the products.
Products must be placed vertically in the canister,
that is, the bottoms of the products must meet the inner bottom of the canister.
Products can be placed at an arbitrary position and with an arbitrary direction in the canister,
but they should not be laid upside-down nor
stacked one on the other.
Products and the inner surface of the canister may touch one another.
The customer requests to make the canister as small as possible.
Your task is to find the smallest possible diameter of the canister
bottom that can contain the two products.
Figure H-1 Example of two products packed in the minimum-sized canister.
Input
The input consists of at most 50 datasets, each in the following format.
n
x
a
,1
y
a
,1
...
x
a
,
n
y
a
,
n
m
x
b
,1
y
b
,1
...
x
b
,
m
y
b
,
m
n
(3 ≤
n
≤ 40) is the number of vertices of the bottom polygon of one of the products.
The following
n
lines have two integers each,
which are the
x-
and
y-
coordinates of the vertices of the bottom polygon.
They are between −1000 and 1000, inclusive.
The vertices are listed in a counter-clockwise order.
The bottom polygon is guaranteed to be convex.
Then comes the description of the bottom polygon of the other product in exactly the same manner.
The end of the input is indicated by a line containing a zero.
Output
For each dataset, output the smallest possible
diameter
of the bottom circle of the canister
that accommodates the two products together.
The output must not contain an error greater than 10
−6
.
Sample Input
3
8 0
7 7
0 6
4
0 0
5 0
5 5
0 5
3
0 0
2 2
0 2
3
3 1
5 1
5 3
5
0 0
3 0
3 1
1 3
0 3
5
0 0
3 0
3 1
1 3
0 3
9
0 0
9 4
13 13
9 22
6 24
-6 24
-9 22
-13 13
-9 4
4
1 0
0 5
-1 0
0 -5
0
Output for the Sample Input
10.625000000000
2.828427124746
5.656854249492
26.000000000000

Submitted solutions:

code_snippet: #include <bits/stdc++.h>
using namespace std;

class point2d {
public:
    double x, y;
    point2d() : x(0.0), y(0.0) {};
    point2d(double x_, double y_) : x(x_), y(y_) {};
    point2d& operator+=(const point2d& p) { x += p.x; y += p.y; return (*this); }
    point2d& operator-=(const point2d& p) { x -= p.x; y -= p.y; return (*this); }
    point2d& operator*=(double v) { x *= v; y *= v; return (*this); }
    point2d operator+(const point2d& p) const { return point2d(*this) += p; }
    point2d operator-(const point2d& p) const { return point2d(*this) -= p; }
    point2d operator*(double v) const { return point2d(*this) *= v; }
    double abs() const {
        return sqrt(x * x + y * y);
    }
    double dot(const point2d& p) const {
        return x * p.x + y * p.y;
    }
};

const double pi = acos(-1.0);

// Q. Can the polygon be placed in range x^2 + y^2 <= R, y >= YL ???
bool check(int N, const vector<point2d>& P, double R, double YL, const vector<vector<vector<point2d> > >& anglist) {
    // Case #1. Two vertices in line y = YL
    for (int i = 0; i < N; i++) {
        double l = -1.0e+9, r = +1.0e+9;
        for (int j = 0; j < N; j++) {
            point2d subp = point2d(0, YL) + anglist[i][(i + 1) % N][j];
            if (subp.y >= R) {
                l = +1.0e+9;
                r = -1.0e+9;
            }
            else {
                double w = sqrt(R * R - subp.y * subp.y);
                l = max(l, -w - subp.x);
                r = min(r, +w - subp.x);
            }
        }
        if (l < r) {
            return true;
        }
    }
    // Case #2. Two vertices in circle's circumference
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < N; j++) {
            if (i == j || (P[j] - P[i]).abs() >= 2 * R) {
                continue;
            }
            double elen = (P[j] - P[i]).abs();
            double subh = sqrt(R * R - elen * elen / 4);
            double l1 = 0.0, r1 = 2 * pi;
            double l2 = 0.0, r2 = 2 * pi;
            bool valid = true;
            for (int k = 0; k < N; k++) {
                point2d subp = point2d(-elen / 2, -subh) + anglist[i][j][k];
                double d = subp.abs();
                if (d >= R + 1.0e-7 || (YL >= 0 && d <= YL)) {
                    valid = false;
                    break;
                }
                double phi = atan2(subp.y, subp.x);
                if (d > -YL) {
                    double g = asin(YL / d);
                    double cl = g - phi;
                    double cr = (pi - g) - phi;
                    while (cl < 0.0) cl += 2 * pi;
                    while (cl >= 2 * pi) cl -= 2 * pi;
                    while (cr < 0.0) cr += 2 * pi;
                    while (cr >= 2 * pi) cr -= 2 * pi;
                    if (cl <= cr) {
                        l1 = max(l1, cl);
                        r1 = min(r1, cr);
                    }
                    else {
                        l2 = max(l2, cl);
                        r2 = min(r2, cr);
                    }
                    if (!((l2 < r2 && l1 <= r1) || (l1 <= r2 && r2 <= r1) || (l1 <= l2 && l2 <= r1))) {
                        valid = false;
                        break;
                    }
                }
            }
            if (valid) {
                return true;
            }
        }
    }
    return false;
}

double min_height(int N, const vector<point2d>& P, double R) {
    vector<vector<vector<point2d> > > anglist(N, vector<vector<point2d> >(N, vector<point2d>(N)));
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < N; j++) {
            if (i == j) {
                continue;
            }
            point2d evec = P[j] - P[i];
            double elen = evec.abs();
            for (int k = 0; k < N; k++) {
                double slen = (P[k] - P[i]).abs();
                double theta = (i != k ? acos(max(min(evec.dot(P[k] - P[i]) / (elen * slen), +1.0), -1.0)) : 0.0);
                if ((k - i + N) % N < (j - i + N) % N) {
                    theta *= -1.0;
                }
                anglist[i][j][k] = point2d(cos(theta), sin(theta)) * slen;
            }
        }
    }
    double hl = 0.0, hr = 2.0 * R;
    while (hr - hl > 1.0e-7) {
        double h = (hl + hr) * 0.5;
        if (check(N, P, R, R - h, anglist) == true) {
            hr = h;
        }
        else {
            hl = h;
        }
    }
    return hr;
}

int main() {
    while (true) {
        int N;
        cin >> N;
        if (N == 0) {
            break;
        }
        vector<point2d> P1(N);
        for (int i = 0; i < N; i++) {
            cin >> P1[i].x >> P1[i].y;
        }
        int M;
        cin >> M;
        vector<point2d> P2(M);
        for (int i = 0; i < M; i++) {
            cin >> P2[i].x >> P2[i].y;
        }
        double l = 0.0, r = 1.0e+4;
        while (r - l > 1.0e-7) {
            double m = (l + r) * 0.5;
            double res1 = min_height(N, P1, m);
            double res2 = min_height(M, P2, m);
            if (res1 + res2 <= 2 * m) {
                r = m;
            }
            else {
                l = m;
            }
        }
        cout.precision(15);
        cout << r * 2.0 << endl;
    }
    return 0;
}
accuracy: 1
time_ms: 7370
memory_kb: 5264
final_rank: 18

code_snippet: #include <cmath>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;

class point2d {
public:
	double x, y;
	point2d() : x(0.0), y(0.0) {};
	point2d(double x_, double y_) : x(x_), y(y_) {};
	point2d& operator+=(const point2d& p) { x += p.x; y += p.y; return (*this); }
	point2d& operator-=(const point2d& p) { x -= p.x; y -= p.y; return (*this); }
	point2d& operator*=(double v) { x *= v; y *= v; return (*this); }
	point2d operator+(const point2d& p) const { return point2d(*this) += p; }
	point2d operator-(const point2d& p) const { return point2d(*this) -= p; }
	point2d operator*(double v) const { return point2d(*this) *= v; }
	double abs() const {
		return sqrt(x * x + y * y);
	}
	double dot(const point2d& p) const {
		return x * p.x + y * p.y;
	}
};

const double pi = acos(-1.0);

// Q. Can the polygon be placed in range x^2 + y^2 <= R, y >= YL ???
bool check(int N, const vector<point2d>& P, double R, double YL, const vector<vector<vector<point2d> > >& anglist) {
	// Case #1. Two vertices in line y = YL
	for (int i = 0; i < N; i++) {
		double l = -1.0e+9, r = +1.0e+9;
		for (int j = 0; j < N; j++) {
			point2d subp = point2d(0, YL) + anglist[i][(i + 1) % N][j];
			if (subp.y >= R) {
				l = +1.0e+9;
				r = -1.0e+9;
			}
			else {
				double w = sqrt(R * R - subp.y * subp.y);
				l = max(l, -w - subp.x);
				r = min(r, +w - subp.x);
			}
		}
		if (l < r) {
			return true;
		}
	}
	// Case #2. Two vertices in circle's circumference
	for (int i = 0; i < N; i++) {
		for (int j = 0; j < N; j++) {
			if (i == j || (P[j] - P[i]).abs() >= 2 * R) {
				continue;
			}
			double elen = (P[j] - P[i]).abs();
			double subh = sqrt(R * R - elen * elen / 4);
			double l1 = 0.0, r1 = 2 * pi;
			double l2 = 0.0, r2 = 2 * pi;
			bool valid = true;
			for (int k = 0; k < N; k++) {
				point2d subp = point2d(-elen / 2, -subh) + anglist[i][j][k];
				double d = subp.abs();
				if (d >= R + 1.0e-7 || (YL >= 0 && d <= YL)) {
					valid = false;
					break;
				}
				double phi = atan2(subp.y, subp.x);
				if (d > -YL) {
					double g = asin(YL / d);
					double cl = g - phi;
					double cr = (pi - g) - phi;
					while (cl < 0.0) cl += 2 * pi;
					while (cl >= 2 * pi) cl -= 2 * pi;
					while (cr < 0.0) cr += 2 * pi;
					while (cr >= 2 * pi) cr -= 2 * pi;
					if (cl <= cr) {
						l1 = max(l1, cl);
						r1 = min(r1, cr);
					}
					else {
						l2 = max(l2, cl);
						r2 = min(r2, cr);
					}
					if (!((l2 < r2 && l1 <= r1) || (l1 <= r2 && r2 <= r1) || (l1 <= l2 && l2 <= r1))) {
						valid = false;
						break;
					}
				}
			}
			if (valid) {
				return true;
			}
		}
	}
	return false;
}

double min_height(int N, const vector<point2d>& P, double R) {
	vector<vector<vector<point2d> > > anglist(N, vector<vector<point2d> >(N, vector<point2d>(N)));
	for (int i = 0; i < N; i++) {
		for (int j = 0; j < N; j++) {
			if (i == j) {
				continue;
			}
			point2d evec = P[j] - P[i];
			double elen = evec.abs();
			for (int k = 0; k < N; k++) {
				double slen = (P[k] - P[i]).abs();
				double theta = (i != k ? acos(max(min(evec.dot(P[k] - P[i]) / (elen * slen), +1.0), -1.0)) : 0.0);
				if ((k - i + N) % N < (j - i + N) % N) {
					theta *= -1.0;
				}
				anglist[i][j][k] = point2d(cos(theta), sin(theta)) * slen;
			}
		}
	}
	double hl = 0.0, hr = 2.0 * R;
	while (hr - hl > 1.0e-7) {
		double h = (hl + hr) * 0.5;
		if (check(N, P, R, R - h, anglist) == true) {
			hr = h;
		}
		else {
			hl = h;
		}
	}
	return hr;
}

int main() {
	while (true) {
		int N;
		cin >> N;
		if (N == 0) {
			break;
		}
		vector<point2d> P1(N);
		for (int i = 0; i < N; i++) {
			cin >> P1[i].x >> P1[i].y;
		}
		int M;
		cin >> M;
		vector<point2d> P2(M);
		for (int i = 0; i < M; i++) {
			cin >> P2[i].x >> P2[i].y;
		}
		double l = 0.0, r = 1.0e+4;
		while (r - l > 1.0e-7) {
			double m = (l + r) * 0.5;
			double res1 = min_height(N, P1, m);
			double res2 = min_height(M, P2, m);
			if (res1 + res2 <= 2 * m) {
				r = m;
			}
			else {
				l = m;
			}
		}
		cout.precision(15);
		cout << r * 2.0 << endl;
	}
	return 0;
}
accuracy: 1
time_ms: 7390
memory_kb: 5236
final_rank: 17

code_snippet: #define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <algorithm>
#include <vector>
#include <cmath>
#include <cstring>
#include <cassert>
#include <random>
typedef long long ll;
//typedef long double ld;
typedef double ld;
typedef std::vector<ld> Vld;
const ld INF = 1e17;
const ld TOL = 1e-7;
const ld PI = acos(-1);
const int LEN = 40;
inline int sign(const ld& x) { return x < -TOL ? -1 : x > TOL; }
inline bool zero(const ld& x) { return !sign(x); }
inline bool eq(const ld& x, const ld& y) { return zero(x - y); }

Vld ans;
int N, M;
struct Pos {
	ld x, y;
	Pos(ld X = 0, ld Y = 0) : x(X), y(Y) {}
	Pos operator + (const Pos& p) const { return { x + p.x, y + p.y }; }
	Pos operator - (const Pos& p) const { return { x - p.x, y - p.y }; }
	Pos operator * (const ld& n) const { return { x * n, y * n }; }
	Pos operator / (const ld& n) const { return { x / n, y / n }; }
	ld operator * (const Pos& p) const { return x * p.x + y * p.y; }
	ld operator / (const Pos& p) const { return x * p.y - y * p.x; }
	Pos& operator += (const Pos& p) { x += p.x; y += p.y; return *this; }
	Pos operator ~ () const { return { -y, x }; }
	Pos rot(ld the) const { return { x * cos(the) - y * sin(the), x * sin(the) + y * cos(the) }; }
	ld Euc() const { return x * x + y * y; }
	ld mag() const { return sqrt(Euc()); }
	Pos unit() const { return *this / mag(); }
	ld rad() const { return atan2(y, x); }
	friend ld rad(const Pos& p1, const Pos& p2) { return atan2l(p1 / p2, p1 * p2); }
	friend std::istream& operator >> (std::istream& is, Pos& p) { is >> p.x >> p.y; return is; }
	friend std::ostream& operator << (std::ostream& os, const Pos& p) { os << "(" << p.x << ", " << p.y << ")"; return os; }
}; const Pos O = Pos(0, 0);
typedef std::vector<Pos> Polygon;
struct Vec {
	ld vy, vx;
	Vec(ld Y = 0, ld X = 0) : vy(Y), vx(X) {}
	bool operator == (const Vec& v) const { return (zero(vy - v.vy) && zero(vx - v.vx)); }
	bool operator < (const Vec& v) const { return zero(vy - v.vy) ? vx < v.vx : vy < v.vy; }
	ld operator * (const Vec& v) const { return vy * v.vy + vx * v.vx; }
	ld operator / (const Vec& v) const { return vy * v.vx - vx * v.vy; }
	Vec operator ~ () const { return { -vx, vy }; }
}; const Vec Zero = { 0, 0 };
struct Line {//ax + by = c
	Vec s;
	ld c;
	Line(Vec V = Vec(0, 0), ld C = 0) : s(V), c(C) {}
	Line(Vec V = Vec(0, 0), Pos p = Pos(0, 0)) : s(V) { c = s.vy * p.x + s.vx * p.y; }
	Line(Pos ps = Pos(0, 0), Pos pe = Pos(0, 0)) {
		ld dy, dx;
		dy = pe.y - ps.y;
		dx = ps.x - pe.x;
		s = Vec(dy, dx);
		c = dy * ps.x + dx * ps.y;
	}
	ld operator / (const Line& l) const { return s / l.s; }
	ld operator * (const Line& l) const { return s * l.s; }
};
Line L(const Pos& s, const Pos& e) { return Line(s, e); }
Line rotate90(const Line& l, const Pos& p) { return Line(~l.s, p); }
Pos intersection(const Line& l1, const Line& l2) {
	Vec v1 = l1.s, v2 = l2.s;
	ld det = v1 / v2;
	return {
		(l1.c * v2.vx - l2.c * v1.vx) / det,
		(l2.c * v1.vy - l1.c * v2.vy) / det,
	};
}
ld cross(const Pos& d1, const Pos& d2, const Pos& d3) { return (d2 - d1) / (d3 - d2); }
int ccw(const Pos& d1, const Pos& d2, const Pos& d3) { return sign(cross(d1, d2, d3)); }
ld dot(const Pos& d1, const Pos& d2, const Pos& d3) { return (d2 - d1) * (d3 - d2); }
ld area(const Polygon& H) {
	ld ret = 0;
	int sz = H.size();
	for (int i = 0; i < sz; i++) ret += H[i] / H[(i + 1) % sz];
	return ret;
}
bool norm(Polygon& H) {
	ld a = area(H);
	if (zero(a)) return 1;
	if (a < 0) std::reverse(H.begin(), H.end());
	return 0;
}
Polygon rotate_and_norm(Polygon B, const int& j0, const Polygon& A, const int& i0, const ld& t) {
	int sz = B.size();
	for (int j = 0; j < sz; j++) B[j] = B[j].rot(t);
	Pos v = A[i0] - B[j0];
	for (int j = 0; j < sz; j++) B[j] += v;
	return B;
}
struct Circle {
	Pos c;
	ld r;
	Circle(Pos C = Pos(0, 0), ld R = 0) : c(C), r(R) {}
	bool operator > (const Pos& p) const { return r > (c - p).mag(); }
	bool operator >= (const Pos& p) const { return r + TOL > (c - p).mag(); }
	bool operator < (const Pos& p) const { return r < (c - p).mag(); }
} INVAL = { { 0, 0 }, -1 };
Circle enclose_circle(const Pos& u, const Pos& v) {
	Pos c = (u + v) * .5;
	return Circle(c, (c - u).mag());
}
Circle enclose_circle(const Pos& u, const Pos& v, const Pos& w) {
	Line l1 = rotate90(L(u, v), (u + v) * .5);
	Line l2 = rotate90(L(v, w), (v + w) * .5);
	if (zero(l1 / l2)) return { { 0, 0 }, -1 };
	Pos c = intersection(l1, l2);
	ld r = (c - u).mag();
	return Circle(c, r);
}
Circle minimum_enclose_circle(std::vector<Pos> P) {
	shuffle(P.begin(), P.end(), std::mt19937(0x14004));
	Circle mec = INVAL;
	int sz = P.size();
	for (int i = 0; i < sz; i++) {
		if (mec.r < -1 || mec < P[i]) {
			mec = Circle(P[i], 0);
			for (int j = 0; j <= i; j++) {
				if (mec < P[j]) {
					Circle ans = enclose_circle(P[i], P[j]);
					if (zero(mec.r)) { mec = ans; continue; }
					Circle l = INVAL, r = INVAL;
					for (int k = 0; k <= j; k++) {
						if (ans < P[k]) {
							int CCW = ccw(P[i], P[j], P[k]);
							Circle c = enclose_circle(P[i], P[j], P[k]);
							if (c.r < 0) continue;
							else if (CCW > 0 && (l.r < 0 || cross(P[i], P[j], c.c) > cross(P[i], P[j], l.c))) l = c;
							else if (CCW < 0 && (r.r < 0 || cross(P[i], P[j], c.c) < cross(P[i], P[j], r.c))) r = c;
						}
					}
					if (l.r < 0 && r.r < 0) mec = ans;
					else if (l.r < 0) mec = r;
					else if (r.r < 0) mec = l;
					else mec = l.r < r.r ? l : r;
				}
			}
		}
	}
	return mec;
}
Circle minimum_enclose_circle(Polygon A, const int& i, Polygon B, const int& j, const ld& d) {
	Pos v = (A[(i + 1) % A.size()] - B[(j + 1) % B.size()]).unit() * d;
	for (Pos& p : B) A.push_back(p + v);
	return minimum_enclose_circle(A);
}
ld ternary_search(const Polygon& A, const int& i, const Polygon& B, const int& j) {
	int a = A.size(), b = B.size();
	const Pos& pa = A[(i + 1) % a], & pb = B[(j + 1) % b];
	ld s = 0, e = (pa - pb).mag(), m1, m2, r1 = 0, r2 = 0;
	int cnt = 25; while (cnt--) {
		m1 = (s + s + e) / 3;
		m2 = (s + e + e) / 3;
		r1 = minimum_enclose_circle(A, i, B, j, m1).r;
		r2 = minimum_enclose_circle(A, i, B, j, m2).r;
		if (r1 > r2) s = m1;
		else e = m2;
	}
	return r2;
}
ld fit(const Polygon& P, const ld& r) {
	auto dist = [&](const Pos& s1, const Pos& s2, const Pos& c) -> ld {
		ld d = cross(s1, s2, c) / (s1 - s2).mag();
		return r + d;
		};
	int sz = P.size();
	ld ret = INF;
	for (int i = 0; i < sz; i++) {
		for (int j = i + 1; j < sz; j++) {
			ld tmp = INF;
			const Pos& p = P[i], & q = P[j];
			Pos mid = (p + q) * .5;
			Pos vec = p - mid;
			ld h = vec.mag();
			if (sign(h - r) > 0) continue;
			ld w = sqrt(r * r - h * h);
			Pos c1 = mid + ~vec.unit() * w;
			Pos c2 = mid - ~vec.unit() * w;
			for (const Pos& c : { c1, c2 }) {
				for (int k = 0; k < sz; k++) {
					const Pos& p0 = P[(k - 1 + sz) % sz], & p1 = P[k], & p2 = P[(k + 1) % sz];
					assert(ccw(p0, p1, p2) >= 0);
					if (k == i || k == j) continue;
					if (sign((P[k] - c).mag() - r) > 0) { tmp = INF; break; }
					if (ccw(p0, p1, c) < 0 && ccw(p1, p2, c) < 0 && dot(p0, p1, c) > 0 && dot(p2, p1, c) > 0) {
						tmp = std::min(tmp, r - (c - p1).mag());
					}
					else tmp = std::min({ tmp, dist(p0, p1, c), dist(p1, p2, c) });
				}
				ret = std::min(ret, tmp);
			}
		}
	}
	return ret;
}
bool fit(const Polygon& A, const Polygon& B, const ld& r) {
	ld da = fit(A, r), db = fit(B, r);
	return sign(r + r - (da + db)) >= 0 ? 1 : 0;
}
ld bi_search(const Polygon& A, const Polygon& B, ld s, ld e) {
	int cnt = 30; while (cnt--) {
		ld m = (s + e) * .5;
		if (fit(A, B, m)) e = m;
		else s = m;
	}
	return (s + e) * .5;
}
bool query() {
	std::cin >> N;
	if (!N) return 0;
	Polygon A(N);
	for (Pos& p : A) std::cin >> p;
	norm(A);
	std::cin >> M;
	Polygon B(M);
	for (Pos& p : B) std::cin >> p;
	norm(B);
	ld ret = INF, r1 = INF;
	ld ra = minimum_enclose_circle(A).r, rb = minimum_enclose_circle(B).r;
	for (int i = 0; i < N; i++) {
		Pos& I0 = A[i], & I1 = A[(i + 1) % N];
		for (int j = 0; j < M; j++) {
			Pos& J0 = B[j], & J1 = B[(j + 1) % M];
			ld t = rad(J0 - J1, I1 - I0);
			Polygon B2 = rotate_and_norm(B, j, A, i, t);
			r1 = std::min(r1, ternary_search(A, i, B2, j));
		}
	}
	ld r2 = bi_search(A, B, std::max(ra, rb), r1);
	ret = std::min({ ret, r1, r2 }) * 2;
	ans.push_back(ret);
	return 1;
}
void solve() {
	std::cin.tie(0)->sync_with_stdio(0);
	std::cout.tie(0);
	std::cout << std::fixed;
	std::cout.precision(15);
	while (query());
	for (const ld& ret : ans) std::cout << ret << "\n";
	return;
}
int main() { solve(); return 0; }//boj20231 Idealistic Canister
accuracy: 1
time_ms: 3680
memory_kb: 3880
final_rank: 2

code_snippet: #define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <algorithm>
#include <vector>
#include <cmath>
#include <cstring>
#include <cassert>
#include <random>
typedef long long ll;
//typedef long double ld;
typedef double ld;
typedef std::vector<ld> Vld;
const ld INF = 1e17;
const ld TOL = 1e-7;
const ld PI = acos(-1);
const int LEN = 40;
inline int sign(const ld& x) { return x < -TOL ? -1 : x > TOL; }
inline bool zero(const ld& x) { return !sign(x); }
inline bool eq(const ld& x, const ld& y) { return zero(x - y); }

Vld ans;
int N, M;
struct Pos {
	ld x, y;
	Pos(ld X = 0, ld Y = 0) : x(X), y(Y) {}
	//bool operator == (const Pos& p) const { return zero(x - p.x) && zero(y - p.y); }
	//bool operator != (const Pos& p) const { return !zero(x - p.x) || !zero(y - p.y); }
	//bool operator < (const Pos& p) const { return zero(x - p.x) ? y < p.y : x < p.x; }
	//bool operator <= (const Pos& p) const { return *this < p || *this == p; }
	Pos operator + (const Pos& p) const { return { x + p.x, y + p.y }; }
	Pos operator - (const Pos& p) const { return { x - p.x, y - p.y }; }
	Pos operator * (const ld& n) const { return { x * n, y * n }; }
	Pos operator / (const ld& n) const { return { x / n, y / n }; }
	ld operator * (const Pos& p) const { return x * p.x + y * p.y; }
	ld operator / (const Pos& p) const { return x * p.y - y * p.x; }
	Pos& operator += (const Pos& p) { x += p.x; y += p.y; return *this; }
	//Pos& operator -= (const Pos& p) { x -= p.x; y -= p.y; return *this; }
	//Pos& operator *= (const ld& n) { x *= scale; y *= n; return *this; }
	//Pos& operator /= (const ld& n) { x /= scale; y /= n; return *this; }
	//Pos operator - () const { return { -x, -y }; }
	Pos operator ~ () const { return { -y, x }; }
	Pos rot(ld the) const { return { x * cos(the) - y * sin(the), x * sin(the) + y * cos(the) }; }
	ld Euc() const { return x * x + y * y; }
	ld mag() const { return sqrt(Euc()); }
	Pos unit() const { return *this / mag(); }
	ld rad() const { return atan2(y, x); }
	friend ld rad(const Pos& p1, const Pos& p2) { return atan2l(p1 / p2, p1 * p2); }
	friend std::istream& operator >> (std::istream& is, Pos& p) { is >> p.x >> p.y; return is; }
	friend std::ostream& operator << (std::ostream& os, const Pos& p) { os << "(" << p.x << ", " << p.y << ")"; return os; }
}; const Pos O = Pos(0, 0);
typedef std::vector<Pos> Polygon;
struct Vec {
	ld vy, vx;
	Vec(ld Y = 0, ld X = 0) : vy(Y), vx(X) {}
	bool operator == (const Vec& v) const { return (zero(vy - v.vy) && zero(vx - v.vx)); }
	bool operator < (const Vec& v) const { return zero(vy - v.vy) ? vx < v.vx : vy < v.vy; }
	ld operator * (const Vec& v) const { return vy * v.vy + vx * v.vx; }
	ld operator / (const Vec& v) const { return vy * v.vx - vx * v.vy; }
	Vec operator ~ () const { return { -vx, vy }; }
}; const Vec Zero = { 0, 0 };
struct Line {//ax + by = c
	Vec s;
	ld c;
	Line(Vec V = Vec(0, 0), ld C = 0) : s(V), c(C) {}
	Line(Vec V = Vec(0, 0), Pos p = Pos(0, 0)) : s(V) { c = s.vy * p.x + s.vx * p.y; }
	Line(Pos ps = Pos(0, 0), Pos pe = Pos(0, 0)) {
		ld dy, dx;
		dy = pe.y - ps.y;
		dx = ps.x - pe.x;
		s = Vec(dy, dx);
		c = dy * ps.x + dx * ps.y;
	}
	ld operator / (const Line& l) const { return s / l.s; }
	ld operator * (const Line& l) const { return s * l.s; }
};
Line L(const Pos& s, const Pos& e) { return Line(s, e); }
Line rotate90(const Line& l, const Pos& p) { return Line(~l.s, p); }
Pos intersection(const Line& l1, const Line& l2) {
	Vec v1 = l1.s, v2 = l2.s;
	ld det = v1 / v2;
	return {
		(l1.c * v2.vx - l2.c * v1.vx) / det,
		(l2.c * v1.vy - l1.c * v2.vy) / det,
	};
}
ld cross(const Pos& d1, const Pos& d2, const Pos& d3) { return (d2 - d1) / (d3 - d2); }
int ccw(const Pos& d1, const Pos& d2, const Pos& d3) { return sign(cross(d1, d2, d3)); }
ld dot(const Pos& d1, const Pos& d2, const Pos& d3) { return (d2 - d1) * (d3 - d2); }
ld area(const Polygon& H) {
	ld ret = 0;
	int sz = H.size();
	for (int i = 0; i < sz; i++) ret += H[i] / H[(i + 1) % sz];
	return ret;
}
bool norm(Polygon& H) {
	ld a = area(H);
	if (zero(a)) return 1;
	if (a < 0) std::reverse(H.begin(), H.end());
	return 0;
}
Polygon rotate_and_norm(Polygon B, const int& j0, const Polygon& A, const int& i0, const ld& t) {
	int sz = B.size();
	for (int j = 0; j < sz; j++) B[j] = B[j].rot(t);
	Pos v = A[i0] - B[j0];
	for (int j = 0; j < sz; j++) B[j] += v;
	return B;
}
struct Circle {
	Pos c;
	ld r;
	Circle(Pos C = Pos(0, 0), ld R = 0) : c(C), r(R) {}
	//bool operator == (const Circle& C) const { return c == C.c && std::abs(r - C.r) < TOL; }
	//bool operator != (const Circle& C) const { return !(*this == C); }
	bool operator > (const Pos& p) const { return r > (c - p).mag(); }
	bool operator >= (const Pos& p) const { return r + TOL > (c - p).mag(); }
	bool operator < (const Pos& p) const { return r < (c - p).mag(); }
} INVAL = { { 0, 0 }, -1 };
Circle enclose_circle(const Pos& u, const Pos& v) {
	Pos c = (u + v) * .5;
	return Circle(c, (c - u).mag());
}
Circle enclose_circle(const Pos& u, const Pos& v, const Pos& w) {
	Line l1 = rotate90(L(u, v), (u + v) * .5);
	Line l2 = rotate90(L(v, w), (v + w) * .5);
	if (zero(l1 / l2)) return { { 0, 0 }, -1 };
	Pos c = intersection(l1, l2);
	ld r = (c - u).mag();
	return Circle(c, r);
}
Circle minimum_enclose_circle(std::vector<Pos> P) {
	shuffle(P.begin(), P.end(), std::mt19937(0x14004));
	Circle mec = INVAL;
	int sz = P.size();
	for (int i = 0; i < sz; i++) {
		if (mec.r < -1 || mec < P[i]) {
			mec = Circle(P[i], 0);
			for (int j = 0; j <= i; j++) {
				if (mec < P[j]) {
					Circle ans = enclose_circle(P[i], P[j]);
					if (zero(mec.r)) { mec = ans; continue; }
					Circle l = INVAL, r = INVAL;
					for (int k = 0; k <= j; k++) {
						if (ans < P[k]) {
							int CCW = ccw(P[i], P[j], P[k]);
							Circle c = enclose_circle(P[i], P[j], P[k]);
							if (c.r < 0) continue;
							else if (CCW > 0 && (l.r < 0 || cross(P[i], P[j], c.c) > cross(P[i], P[j], l.c))) l = c;
							else if (CCW < 0 && (r.r < 0 || cross(P[i], P[j], c.c) < cross(P[i], P[j], r.c))) r = c;
						}
					}
					if (l.r < 0 && r.r < 0) mec = ans;
					else if (l.r < 0) mec = r;
					else if (r.r < 0) mec = l;
					else mec = l.r < r.r ? l : r;
				}
			}
		}
	}
	return mec;
}
Circle minimum_enclose_circle(Polygon A, const int& i, const Polygon& B, const int& j, const ld& d) {
	Pos v = (A[(i + 1) % A.size()] - B[(j + 1) % B.size()]).unit() * d;
	for (const Pos& p : B) A.push_back(p + v);
	return minimum_enclose_circle(A);
}
ld ternary_search(const Polygon& A, const int& i, const Polygon& B, const int& j) {
	int a = A.size(), b = B.size();
	const Pos& pa = A[(i + 1) % a], & pb = B[(j + 1) % b];
	ld s = 0, e = (pa - pb).mag(), m1, m2, r1 = 0, r2 = 0;
	int cnt = 25; while (cnt--) {
		m1 = (s + s + e) / 3;
		m2 = (s + e + e) / 3;
		r1 = minimum_enclose_circle(A, i, B, j, m1).r;
		r2 = minimum_enclose_circle(A, i, B, j, m2).r;
		if (r1 > r2) s = m1;
		else e = m2;
	}
	return r2;
}
ld fit(const Polygon& P, const ld& r) {
	auto dist = [&](const Pos& s1, const Pos& s2, const Pos& c) -> ld {
		ld d = cross(s1, s2, c) / (s1 - s2).mag();
		return r + d;
		};
	int sz = P.size();
	ld ret = INF;
	for (int i = 0; i < sz; i++) {
		for (int j = i + 1; j < sz; j++) {
			ld tmp = INF;
			const Pos& p = P[i], & q = P[j];
			Pos mid = (p + q) * .5;
			Pos vec = p - mid;
			ld h = vec.mag();
			if (sign(h - r) > 0) continue;
			ld w = sqrt(r * r - h * h);
			Pos c1 = mid + ~vec.unit() * w;
			Pos c2 = mid - ~vec.unit() * w;
			for (const Pos& c : { c1, c2 }) {
				for (int k = 0; k < sz; k++) {
					const Pos& p0 = P[(k - 1 + sz) % sz], & p1 = P[k], & p2 = P[(k + 1) % sz];
					assert(ccw(p0, p1, p2) >= 0);
					if (k == i || k == j) continue;
					if (sign((P[k] - c).mag() - r) > 0) { tmp = INF; break; }
					if (ccw(p0, p1, c) < 0 && ccw(p1, p2, c) < 0 && dot(p0, p1, c) > 0 && dot(p2, p1, c) > 0) {
						tmp = std::min(tmp, r - (c - p1).mag());
					}
					else tmp = std::min({ tmp, dist(p0, p1, c), dist(p1, p2, c) });
				}
				ret = std::min(ret, tmp);
			}
		}
	}
	return ret;
}
bool fit(const Polygon& A, const Polygon& B, const ld& r) {
	ld da = fit(A, r), db = fit(B, r);
	return sign(r + r - (da + db)) >= 0 ? 1 : 0;
}
ld bi_search(const Polygon& A, const Polygon& B, ld s, ld e) {
	int cnt = 30; while (cnt--) {
		ld m = (s + e) * .5;
		if (fit(A, B, m)) e = m;
		else s = m;
	}
	return (s + e) * .5;
}
bool query() {
	std::cin >> N;
	if (!N) return 0;
	Polygon A(N);
	for (Pos& p : A) std::cin >> p;
	norm(A);
	std::cin >> M;
	Polygon B(M);
	for (Pos& p : B) std::cin >> p;
	norm(B);
	ld ret = INF, r1 = INF;
	ld ra = minimum_enclose_circle(A).r, rb = minimum_enclose_circle(B).r;
	for (int i = 0; i < N; i++) {
		Pos& I0 = A[i], & I1 = A[(i + 1) % N];
		for (int j = 0; j < M; j++) {
			Pos& J0 = B[j], & J1 = B[(j + 1) % M];
			ld t = rad(J0 - J1, I1 - I0);
			Polygon B2 = rotate_and_norm(B, j, A, i, t);
			r1 = std::min(r1, ternary_search(A, i, B2, j));
		}
	}
	ld r2 = bi_search(A, B, std::max(ra, rb), r1);
	ret = std::min({ ret, r1, r2 }) * 2;
	ans.push_back(ret);
	return 1;
}
void solve() {
	std::cin.tie(0)->sync_with_stdio(0);
	std::cout.tie(0);
	std::cout << std::fixed;
	std::cout.precision(15);
	while (query());
	for (const ld& ret : ans) std::cout << ret << "\n";
	return;
}
int main() { solve(); return 0; }//boj20231 Idealistic Canister
accuracy: 1
time_ms: 3800
memory_kb: 3856
final_rank: 3

code_snippet: #define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <algorithm>
#include <vector>
#include <cmath>
#include <cstring>
#include <cassert>
#include <random>
typedef long long ll;
//typedef long double ld;
typedef double ld;
typedef std::vector<ld> Vld;
const ld INF = 1e17;
const ld TOL = 1e-7;
const ld PI = acos(-1);
const int LEN = 40;
inline int sign(const ld& x) { return x < -TOL ? -1 : x > TOL; }
inline bool zero(const ld& x) { return !sign(x); }
inline bool eq(const ld& x, const ld& y) { return zero(x - y); }

Vld ans;
int N, M;
struct Pos {
	ld x, y;
	Pos(ld X = 0, ld Y = 0) : x(X), y(Y) {}
	//bool operator == (const Pos& p) const { return zero(x - p.x) && zero(y - p.y); }
	//bool operator != (const Pos& p) const { return !zero(x - p.x) || !zero(y - p.y); }
	//bool operator < (const Pos& p) const { return zero(x - p.x) ? y < p.y : x < p.x; }
	//bool operator <= (const Pos& p) const { return *this < p || *this == p; }
	Pos operator + (const Pos& p) const { return { x + p.x, y + p.y }; }
	Pos operator - (const Pos& p) const { return { x - p.x, y - p.y }; }
	Pos operator * (const ld& n) const { return { x * n, y * n }; }
	Pos operator / (const ld& n) const { return { x / n, y / n }; }
	ld operator * (const Pos& p) const { return x * p.x + y * p.y; }
	ld operator / (const Pos& p) const { return x * p.y - y * p.x; }
	Pos& operator += (const Pos& p) { x += p.x; y += p.y; return *this; }
	//Pos& operator -= (const Pos& p) { x -= p.x; y -= p.y; return *this; }
	//Pos& operator *= (const ld& n) { x *= scale; y *= n; return *this; }
	//Pos& operator /= (const ld& n) { x /= scale; y /= n; return *this; }
	//Pos operator - () const { return { -x, -y }; }
	Pos operator ~ () const { return { -y, x }; }
	Pos rot(ld the) const { return { x * cos(the) - y * sin(the), x * sin(the) + y * cos(the) }; }
	ld Euc() const { return x * x + y * y; }
	ld mag() const { return sqrt(Euc()); }
	Pos unit() const { return *this / mag(); }
	ld rad() const { return atan2(y, x); }
	friend ld rad(const Pos& p1, const Pos& p2) { return atan2l(p1 / p2, p1 * p2); }
	friend std::istream& operator >> (std::istream& is, Pos& p) { is >> p.x >> p.y; return is; }
	friend std::ostream& operator << (std::ostream& os, const Pos& p) { os << "(" << p.x << ", " << p.y << ")"; return os; }
}; const Pos O = Pos(0, 0);
typedef std::vector<Pos> Polygon;
struct Vec {
	ld vy, vx;
	Vec(ld Y = 0, ld X = 0) : vy(Y), vx(X) {}
	bool operator == (const Vec& v) const { return (zero(vy - v.vy) && zero(vx - v.vx)); }
	bool operator < (const Vec& v) const { return zero(vy - v.vy) ? vx < v.vx : vy < v.vy; }
	ld operator * (const Vec& v) const { return vy * v.vy + vx * v.vx; }
	ld operator / (const Vec& v) const { return vy * v.vx - vx * v.vy; }
	Vec operator ~ () const { return { -vx, vy }; }
}; const Vec Zero = { 0, 0 };
struct Line {//ax + by = c
	Vec s;
	ld c;
	Line(Vec V = Vec(0, 0), ld C = 0) : s(V), c(C) {}
	Line(Vec V = Vec(0, 0), Pos p = Pos(0, 0)) : s(V) { c = s.vy * p.x + s.vx * p.y; }
	Line(Pos ps = Pos(0, 0), Pos pe = Pos(0, 0)) {
		ld dy, dx;
		dy = pe.y - ps.y;
		dx = ps.x - pe.x;
		s = Vec(dy, dx);
		c = dy * ps.x + dx * ps.y;
	}
	ld operator / (const Line& l) const { return s / l.s; }
	ld operator * (const Line& l) const { return s * l.s; }
};
Line L(const Pos& s, const Pos& e) { return Line(s, e); }
Line rotate90(const Line& l, const Pos& p) { return Line(~l.s, p); }
Pos intersection(const Line& l1, const Line& l2) {
	Vec v1 = l1.s, v2 = l2.s;
	ld det = v1 / v2;
	return {
		(l1.c * v2.vx - l2.c * v1.vx) / det,
		(l2.c * v1.vy - l1.c * v2.vy) / det,
	};
}
ld cross(const Pos& d1, const Pos& d2, const Pos& d3) { return (d2 - d1) / (d3 - d2); }
int ccw(const Pos& d1, const Pos& d2, const Pos& d3) { return sign(cross(d1, d2, d3)); }
ld dot(const Pos& d1, const Pos& d2, const Pos& d3) { return (d2 - d1) * (d3 - d2); }
ld area(const Polygon& H) {
	ld ret = 0;
	int sz = H.size();
	for (int i = 0; i < sz; i++) ret += H[i] / H[(i + 1) % sz];
	return ret;
}
bool norm(Polygon& H) {
	ld a = area(H);
	if (zero(a)) return 1;
	if (a < 0) std::reverse(H.begin(), H.end());
	return 0;
}
Polygon rotate_and_norm(Polygon B, const int& j0, const Polygon& A, const int& i0, const ld& t) {
	int sz = B.size();
	for (int j = 0; j < sz; j++) B[j] = B[j].rot(t);
	Pos v = A[i0] - B[j0];
	for (int j = 0; j < sz; j++) B[j] += v;
	return B;
}
struct Circle {
	Pos c;
	ld r;
	Circle(Pos C = Pos(0, 0), ld R = 0) : c(C), r(R) {}
	//bool operator == (const Circle& C) const { return c == C.c && std::abs(r - C.r) < TOL; }
	//bool operator != (const Circle& C) const { return !(*this == C); }
	bool operator > (const Pos& p) const { return r > (c - p).mag(); }
	bool operator >= (const Pos& p) const { return r + TOL > (c - p).mag(); }
	bool operator < (const Pos& p) const { return r < (c - p).mag(); }
} INVAL = { { 0, 0 }, -1 };
Circle enclose_circle(const Pos& u, const Pos& v) {
	Pos c = (u + v) * .5;
	return Circle(c, (c - u).mag());
}
Circle enclose_circle(const Pos& u, const Pos& v, const Pos& w) {
	Line l1 = rotate90(L(u, v), (u + v) * .5);
	Line l2 = rotate90(L(v, w), (v + w) * .5);
	if (zero(l1 / l2)) return { { 0, 0 }, -1 };
	Pos c = intersection(l1, l2);
	ld r = (c - u).mag();
	return Circle(c, r);
}
Circle minimum_enclose_circle(std::vector<Pos> P) {
	shuffle(P.begin(), P.end(), std::mt19937(0x14004));
	Circle mec = INVAL;
	int sz = P.size();
	for (int i = 0; i < sz; i++) {
		if (mec.r < -1 || mec < P[i]) {
			mec = Circle(P[i], 0);
			for (int j = 0; j <= i; j++) {
				if (mec < P[j]) {
					Circle ans = enclose_circle(P[i], P[j]);
					if (zero(mec.r)) { mec = ans; continue; }
					Circle l = INVAL, r = INVAL;
					for (int k = 0; k <= j; k++) {
						if (ans < P[k]) {
							int CCW = ccw(P[i], P[j], P[k]);
							Circle c = enclose_circle(P[i], P[j], P[k]);
							if (c.r < 0) continue;
							else if (CCW > 0 && (l.r < 0 || cross(P[i], P[j], c.c) > cross(P[i], P[j], l.c))) l = c;
							else if (CCW < 0 && (r.r < 0 || cross(P[i], P[j], c.c) < cross(P[i], P[j], r.c))) r = c;
						}
					}
					if (l.r < 0 && r.r < 0) mec = ans;
					else if (l.r < 0) mec = r;
					else if (r.r < 0) mec = l;
					else mec = l.r < r.r ? l : r;
				}
			}
		}
	}
	return mec;
}
Circle minimum_enclose_circle(Polygon A, const int& i, Polygon B, const int& j, const ld& d) {
	Pos v = (A[(i + 1) % A.size()] - B[(j + 1) % B.size()]).unit() * d;
	for (Pos& p : B) A.push_back(p + v);
	return minimum_enclose_circle(A);
}
ld ternary_search(const Polygon& A, const int& i, const Polygon& B, const int& j) {
	int a = A.size(), b = B.size();
	const Pos& pa = A[(i + 1) % a], & pb = B[(j + 1) % b];
	ld s = 0, e = (pa - pb).mag(), m1, m2, r1 = 0, r2 = 0;
	int cnt = 25; while (cnt--) {
		m1 = (s + s + e) / 3;
		m2 = (s + e + e) / 3;
		r1 = minimum_enclose_circle(A, i, B, j, m1).r;
		r2 = minimum_enclose_circle(A, i, B, j, m2).r;
		if (r1 > r2) s = m1;
		else e = m2;
	}
	return r2;
}
ld fit(const Polygon& P, const ld& r) {
	auto dist = [&](const Pos& s1, const Pos& s2, const Pos& c) -> ld {
		ld d = cross(s1, s2, c) / (s1 - s2).mag();
		return r + d;
		};
	int sz = P.size();
	ld ret = INF;
	for (int i = 0; i < sz; i++) {
		for (int j = i + 1; j < sz; j++) {
			ld tmp = INF;
			const Pos& p = P[i], & q = P[j];
			Pos mid = (p + q) * .5;
			Pos vec = p - mid;
			ld h = vec.mag();
			if (sign(h - r) > 0) continue;
			ld w = sqrt(r * r - h * h);
			Pos c1 = mid + ~vec.unit() * w;
			Pos c2 = mid - ~vec.unit() * w;
			for (const Pos& c : { c1, c2 }) {
				for (int k = 0; k < sz; k++) {
					const Pos& p0 = P[(k - 1 + sz) % sz], & p1 = P[k], & p2 = P[(k + 1) % sz];
					assert(ccw(p0, p1, p2) >= 0);
					if (k == i || k == j) continue;
					if (sign((P[k] - c).mag() - r) > 0) { tmp = INF; break; }
					if (ccw(p0, p1, c) < 0 && ccw(p1, p2, c) < 0 && dot(p0, p1, c) > 0 && dot(p2, p1, c) > 0) {
						tmp = std::min(tmp, r - (c - p1).mag());
					}
					else tmp = std::min({ tmp, dist(p0, p1, c), dist(p1, p2, c) });
				}
				ret = std::min(ret, tmp);
			}
		}
	}
	return ret;
}
bool fit(const Polygon& A, const Polygon& B, const ld& r) {
	ld da = fit(A, r), db = fit(B, r);
	return sign(r + r - (da + db)) >= 0 ? 1 : 0;
}
ld bi_search(const Polygon& A, const Polygon& B, ld s, ld e) {
	int cnt = 30; while (cnt--) {
		ld m = (s + e) * .5;
		if (fit(A, B, m)) e = m;
		else s = m;
	}
	return (s + e) * .5;
}
bool query() {
	std::cin >> N;
	if (!N) return 0;
	Polygon A(N);
	for (Pos& p : A) std::cin >> p;
	norm(A);
	std::cin >> M;
	Polygon B(M);
	for (Pos& p : B) std::cin >> p;
	norm(B);
	ld ret = INF, r1 = INF;
	ld ra = minimum_enclose_circle(A).r, rb = minimum_enclose_circle(B).r;
	for (int i = 0; i < N; i++) {
		Pos& I0 = A[i], & I1 = A[(i + 1) % N];
		for (int j = 0; j < M; j++) {
			Pos& J0 = B[j], & J1 = B[(j + 1) % M];
			ld t = rad(J0 - J1, I1 - I0);
			Polygon B2 = rotate_and_norm(B, j, A, i, t);
			r1 = std::min(r1, ternary_search(A, i, B2, j));
		}
	}
	ld r2 = bi_search(A, B, std::max(ra, rb), r1);
	ret = std::min({ ret, r1, r2 }) * 2;
	ans.push_back(ret);
	return 1;
}
void solve() {
	std::cin.tie(0)->sync_with_stdio(0);
	std::cout.tie(0);
	std::cout << std::fixed;
	std::cout.precision(15);
	while (query());
	for (const ld& ret : ans) std::cout << ret << "\n";
	return;
}
int main() { solve(); return 0; }//boj20231 Idealistic Canister
accuracy: 1
time_ms: 3670
memory_kb: 3860
final_rank: 1

code_snippet: #define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <algorithm>
#include <vector>
#include <cmath>
#include <cstring>
#include <cassert>
#include <random>
typedef long long ll;
//typedef long double ld;
typedef double ld;
typedef std::vector<ld> Vld;
const ld INF = 1e17;
const ld TOL = 1e-7;
const ld PI = acos(-1);
const int LEN = 40;
inline int sign(const ld& x) { return x < -TOL ? -1 : x > TOL; }
inline bool zero(const ld& x) { return !sign(x); }
inline bool eq(const ld& x, const ld& y) { return zero(x - y); }

Vld ans;
int N, M;
struct Pos {
	ld x, y;
	Pos(ld X = 0, ld Y = 0) : x(X), y(Y) {}
	//bool operator == (const Pos& p) const { return zero(x - p.x) && zero(y - p.y); }
	//bool operator != (const Pos& p) const { return !zero(x - p.x) || !zero(y - p.y); }
	//bool operator < (const Pos& p) const { return zero(x - p.x) ? y < p.y : x < p.x; }
	//bool operator <= (const Pos& p) const { return *this < p || *this == p; }
	Pos operator + (const Pos& p) const { return { x + p.x, y + p.y }; }
	Pos operator - (const Pos& p) const { return { x - p.x, y - p.y }; }
	Pos operator * (const ld& n) const { return { x * n, y * n }; }
	Pos operator / (const ld& n) const { return { x / n, y / n }; }
	ld operator * (const Pos& p) const { return x * p.x + y * p.y; }
	ld operator / (const Pos& p) const { return x * p.y - y * p.x; }
	Pos& operator += (const Pos& p) { x += p.x; y += p.y; return *this; }
	//Pos& operator -= (const Pos& p) { x -= p.x; y -= p.y; return *this; }
	//Pos& operator *= (const ld& n) { x *= scale; y *= n; return *this; }
	//Pos& operator /= (const ld& n) { x /= scale; y /= n; return *this; }
	//Pos operator - () const { return { -x, -y }; }
	Pos operator ~ () const { return { -y, x }; }
	Pos rot(ld the) const { return { x * cos(the) - y * sin(the), x * sin(the) + y * cos(the) }; }
	ld Euc() const { return x * x + y * y; }
	ld mag() const { return sqrt(Euc()); }
	Pos unit() const { return *this / mag(); }
	ld rad() const { return atan2(y, x); }
	friend ld rad(const Pos& p1, const Pos& p2) { return atan2l(p1 / p2, p1 * p2); }
	friend std::istream& operator >> (std::istream& is, Pos& p) { is >> p.x >> p.y; return is; }
	friend std::ostream& operator << (std::ostream& os, const Pos& p) { os << "(" << p.x << ", " << p.y << ")"; return os; }
}; const Pos O = Pos(0, 0);
typedef std::vector<Pos> Polygon;
struct Vec {
	ld vy, vx;
	Vec(ld Y = 0, ld X = 0) : vy(Y), vx(X) {}
	bool operator == (const Vec& v) const { return (zero(vy - v.vy) && zero(vx - v.vx)); }
	bool operator < (const Vec& v) const { return zero(vy - v.vy) ? vx < v.vx : vy < v.vy; }
	ld operator * (const Vec& v) const { return vy * v.vy + vx * v.vx; }
	ld operator / (const Vec& v) const { return vy * v.vx - vx * v.vy; }
	Vec operator ~ () const { return { -vx, vy }; }
}; const Vec Zero = { 0, 0 };
struct Line {//ax + by = c
	Vec s;
	ld c;
	Line(Vec V = Vec(0, 0), ld C = 0) : s(V), c(C) {}
	Line(Vec V = Vec(0, 0), Pos p = Pos(0, 0)) : s(V) { c = s.vy * p.x + s.vx * p.y; }
	Line(Pos ps = Pos(0, 0), Pos pe = Pos(0, 0)) {
		ld dy, dx;
		dy = pe.y - ps.y;
		dx = ps.x - pe.x;
		s = Vec(dy, dx);
		c = dy * ps.x + dx * ps.y;
	}
	ld operator / (const Line& l) const { return s / l.s; }
	ld operator * (const Line& l) const { return s * l.s; }
};
Line L(const Pos& s, const Pos& e) { return Line(s, e); }
Line rotate90(const Line& l, const Pos& p) { return Line(~l.s, p); }
Pos intersection(const Line& l1, const Line& l2) {
	Vec v1 = l1.s, v2 = l2.s;
	ld det = v1 / v2;
	return {
		(l1.c * v2.vx - l2.c * v1.vx) / det,
		(l2.c * v1.vy - l1.c * v2.vy) / det,
	};
}
ld cross(const Pos& d1, const Pos& d2, const Pos& d3) { return (d2 - d1) / (d3 - d2); }
int ccw(const Pos& d1, const Pos& d2, const Pos& d3) { return sign(cross(d1, d2, d3)); }
ld dot(const Pos& d1, const Pos& d2, const Pos& d3) { return (d2 - d1) * (d3 - d2); }
ld area(const Polygon& H) {
	ld ret = 0;
	int sz = H.size();
	for (int i = 0; i < sz; i++) ret += H[i] / H[(i + 1) % sz];
	return ret;
}
bool norm(Polygon& H) {
	ld a = area(H);
	if (zero(a)) return 1;
	if (a < 0) std::reverse(H.begin(), H.end());
	return 0;
}
Polygon rotate_and_norm(Polygon B, const int& j0, const Polygon& A, const int& i0, const ld& t) {
	int sz = B.size();
	for (int j = 0; j < sz; j++) B[j] = B[j].rot(t);
	Pos v = A[i0] - B[j0];
	for (int j = 0; j < sz; j++) B[j] += v;
	return B;
}
struct Circle {
	Pos c;
	ld r;
	Circle(Pos C = Pos(0, 0), ld R = 0) : c(C), r(R) {}
	//bool operator == (const Circle& C) const { return c == C.c && std::abs(r - C.r) < TOL; }
	//bool operator != (const Circle& C) const { return !(*this == C); }
	bool operator > (const Pos& p) const { return r > (c - p).mag(); }
	bool operator >= (const Pos& p) const { return r + TOL > (c - p).mag(); }
	bool operator < (const Pos& p) const { return r < (c - p).mag(); }
} INVAL = { { 0, 0 }, -1 };
Circle enclose_circle(const Pos& u, const Pos& v) {
	Pos c = (u + v) * .5;
	return Circle(c, (c - u).mag());
}
Circle enclose_circle(const Pos& u, const Pos& v, const Pos& w) {
	Line l1 = rotate90(L(u, v), (u + v) * .5);
	Line l2 = rotate90(L(v, w), (v + w) * .5);
	if (zero(l1 / l2)) return { { 0, 0 }, -1 };
	Pos c = intersection(l1, l2);
	ld r = (c - u).mag();
	return Circle(c, r);
}
Circle minimum_enclose_circle(std::vector<Pos> P) {
	shuffle(P.begin(), P.end(), std::mt19937(0x14004));
	Circle mec = INVAL;
	int sz = P.size();
	for (int i = 0; i < sz; i++) {
		if (mec.r < -1 || mec < P[i]) {
			mec = Circle(P[i], 0);
			for (int j = 0; j <= i; j++) {
				if (mec < P[j]) {
					Circle ans = enclose_circle(P[i], P[j]);
					if (zero(mec.r)) { mec = ans; continue; }
					Circle l = INVAL, r = INVAL;
					for (int k = 0; k <= j; k++) {
						if (ans < P[k]) {
							int CCW = ccw(P[i], P[j], P[k]);
							Circle c = enclose_circle(P[i], P[j], P[k]);
							if (c.r < 0) continue;
							else if (CCW > 0 && (l.r < 0 || cross(P[i], P[j], c.c) > cross(P[i], P[j], l.c))) l = c;
							else if (CCW < 0 && (r.r < 0 || cross(P[i], P[j], c.c) < cross(P[i], P[j], r.c))) r = c;
						}
					}
					if (l.r < 0 && r.r < 0) mec = ans;
					else if (l.r < 0) mec = r;
					else if (r.r < 0) mec = l;
					else mec = l.r < r.r ? l : r;
				}
			}
		}
	}
	return mec;
}
Circle minimum_enclose_circle(Polygon A, int i, Polygon B, int j, ld d) {
	Polygon V;
	Pos v = (A[(i + 1) % A.size()] - B[(j + 1) % B.size()]).unit() * d;
	for (Pos& p : B) p += v;
	for (const Pos& p : A) V.push_back(p);
	for (const Pos& p : B) V.push_back(p);
	return minimum_enclose_circle(V);
}
ld ternary_search(const Polygon& A, const int& i, const Polygon& B, const int& j) {
	int a = A.size(), b = B.size();
	const Pos& pa = A[(i + 1) % a], & pb = B[(j + 1) % b];
	ld s = 0, e = (pa - pb).mag(), m1, m2, r1 = 0, r2 = 0;
	int cnt = 25; while (cnt--) {
		m1 = (s + s + e) / 3;
		m2 = (s + e + e) / 3;
		r1 = minimum_enclose_circle(A, i, B, j, m1).r;
		r2 = minimum_enclose_circle(A, i, B, j, m2).r;
		if (r1 > r2) s = m1;
		else e = m2;
	}
	return r2;
}
ld fit(const Polygon& P, const ld& r) {
	auto dist = [&](const Pos& s1, const Pos& s2, const Pos& c) -> ld {
		ld d = cross(s1, s2, c) / (s1 - s2).mag();
		return r + d;
		};
	int sz = P.size();
	ld ret = INF;
	for (int i = 0; i < sz; i++) {
		for (int j = i + 1; j < sz; j++) {
			ld tmp = INF;
			const Pos& p = P[i], & q = P[j];
			Pos mid = (p + q) * .5;
			Pos vec = p - mid;
			ld h = vec.mag();
			if (sign(h - r) > 0) continue;
			ld w = sqrt(r * r - h * h);
			Pos c1 = mid + ~vec.unit() * w;
			Pos c2 = mid - ~vec.unit() * w;
			for (const Pos& c : { c1, c2 }) {
				for (int k = 0; k < sz; k++) {
					const Pos& p0 = P[(k - 1 + sz) % sz], & p1 = P[k], & p2 = P[(k + 1) % sz];
					assert(ccw(p0, p1, p2) >= 0);
					if (k == i || k == j) continue;
					if (sign((P[k] - c).mag() - r) > 0) { tmp = INF; break; }
					if (ccw(p0, p1, c) < 0 && ccw(p1, p2, c) < 0 && dot(p0, p1, c) > 0 && dot(p2, p1, c) > 0) {
						tmp = std::min(tmp, r - (c - p1).mag());
					}
					else tmp = std::min({ tmp, dist(p0, p1, c), dist(p1, p2, c) });
				}
				ret = std::min(ret, tmp);
			}
		}
	}
	return ret;
}
bool fit(const Polygon& A, const Polygon& B, const ld& r) {
	ld da = fit(A, r), db = fit(B, r);
	return sign(r + r - (da + db)) >= 0 ? 1 : 0;
}
ld bi_search(const Polygon& A, const Polygon& B, ld s, ld e) {
	int cnt = 30; while (cnt--) {
		ld m = (s + e) * .5;
		if (fit(A, B, m)) e = m;
		else s = m;
	}
	return (s + e) * .5;
}
bool query() {
	std::cin >> N;
	if (!N) return 0;
	Polygon A(N);
	for (Pos& p : A) std::cin >> p;
	norm(A);
	std::cin >> M;
	Polygon B(M);
	for (Pos& p : B) std::cin >> p;
	norm(B);
	ld ret = INF, r1 = INF;
	ld ra = minimum_enclose_circle(A).r, rb = minimum_enclose_circle(B).r;
	for (int i = 0; i < N; i++) {
		Pos& I0 = A[i], & I1 = A[(i + 1) % N];
		for (int j = 0; j < M; j++) {
			Pos& J0 = B[j], & J1 = B[(j + 1) % M];
			ld t = rad(J0 - J1, I1 - I0);
			Polygon B2 = rotate_and_norm(B, j, A, i, t);
			r1 = std::min(r1, ternary_search(A, i, B2, j));
		}
	}
	ld r2 = bi_search(A, B, std::max(ra, rb), r1);
	ret = std::min({ ret, r1, r2 }) * 2;
	ans.push_back(ret);
	return 1;
}
void solve() {
	std::cin.tie(0)->sync_with_stdio(0);
	std::cout.tie(0);
	std::cout << std::fixed;
	std::cout.precision(15);
	while (query());
	for (const ld& ret : ans) std::cout << ret << "\n";
	return;
}
int main() { solve(); return 0; }//boj20231 Idealistic Canister
accuracy: 1
time_ms: 3760
memory_kb: 3912
final_rank: 4

code_snippet: #define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <algorithm>
#include <vector>
#include <cmath>
#include <cstring>
#include <cassert>
#include <random>
typedef long long ll;
//typedef long double ld;
typedef double ld;
typedef std::vector<ld> Vld;
const ld INF = 1e17;
const ld TOL = 1e-7;
const ld PI = acos(-1);
const int LEN = 40;
inline int sign(const ld& x) { return x < -TOL ? -1 : x > TOL; }
inline bool zero(const ld& x) { return !sign(x); }
inline bool eq(const ld& x, const ld& y) { return zero(x - y); }

Vld ans;
int N, M;
struct Pos {
	ld x, y;
	Pos(ld X = 0, ld Y = 0) : x(X), y(Y) {}
	//bool operator == (const Pos& p) const { return zero(x - p.x) && zero(y - p.y); }
	//bool operator != (const Pos& p) const { return !zero(x - p.x) || !zero(y - p.y); }
	//bool operator < (const Pos& p) const { return zero(x - p.x) ? y < p.y : x < p.x; }
	//bool operator <= (const Pos& p) const { return *this < p || *this == p; }
	Pos operator + (const Pos& p) const { return { x + p.x, y + p.y }; }
	Pos operator - (const Pos& p) const { return { x - p.x, y - p.y }; }
	Pos operator * (const ld& n) const { return { x * n, y * n }; }
	Pos operator / (const ld& n) const { return { x / n, y / n }; }
	ld operator * (const Pos& p) const { return x * p.x + y * p.y; }
	ld operator / (const Pos& p) const { return x * p.y - y * p.x; }
	Pos& operator += (const Pos& p) { x += p.x; y += p.y; return *this; }
	//Pos& operator -= (const Pos& p) { x -= p.x; y -= p.y; return *this; }
	//Pos& operator *= (const ld& n) { x *= scale; y *= n; return *this; }
	//Pos& operator /= (const ld& n) { x /= scale; y /= n; return *this; }
	//Pos operator - () const { return { -x, -y }; }
	Pos operator ~ () const { return { -y, x }; }
	Pos rot(ld the) const { return { x * cos(the) - y * sin(the), x * sin(the) + y * cos(the) }; }
	ld Euc() const { return x * x + y * y; }
	ld mag() const { return sqrt(Euc()); }
	Pos unit() const { return *this / mag(); }
	ld rad() const { return atan2(y, x); }
	friend ld rad(const Pos& p1, const Pos& p2) { return atan2l(p1 / p2, p1 * p2); }
	friend std::istream& operator >> (std::istream& is, Pos& p) { is >> p.x >> p.y; return is; }
	friend std::ostream& operator << (std::ostream& os, const Pos& p) { os << "(" << p.x << ", " << p.y << ")"; return os; }
}; const Pos O = Pos(0, 0);
typedef std::vector<Pos> Polygon;
struct Vec {
	ld vy, vx;
	Vec(ld Y = 0, ld X = 0) : vy(Y), vx(X) {}
	bool operator == (const Vec& v) const { return (zero(vy - v.vy) && zero(vx - v.vx)); }
	bool operator < (const Vec& v) const { return zero(vy - v.vy) ? vx < v.vx : vy < v.vy; }
	ld operator * (const Vec& v) const { return vy * v.vy + vx * v.vx; }
	ld operator / (const Vec& v) const { return vy * v.vx - vx * v.vy; }
	Vec operator ~ () const { return { -vx, vy }; }
}; const Vec Zero = { 0, 0 };
struct Line {//ax + by = c
	Vec s;
	ld c;
	Line(Vec V = Vec(0, 0), ld C = 0) : s(V), c(C) {}
	Line(Vec V = Vec(0, 0), Pos p = Pos(0, 0)) : s(V) { c = s.vy * p.x + s.vx * p.y; }
	Line(Pos ps = Pos(0, 0), Pos pe = Pos(0, 0)) {
		ld dy, dx;
		dy = pe.y - ps.y;
		dx = ps.x - pe.x;
		s = Vec(dy, dx);
		c = dy * ps.x + dx * ps.y;
	}
	ld operator / (const Line& l) const { return s / l.s; }
	ld operator * (const Line& l) const { return s * l.s; }
};
Line L(const Pos& s, const Pos& e) { return Line(s, e); }
Line rotate90(const Line& l, const Pos& p) { return Line(~l.s, p); }
Pos intersection(const Line& l1, const Line& l2) {
	Vec v1 = l1.s, v2 = l2.s;
	ld det = v1 / v2;
	return {
		(l1.c * v2.vx - l2.c * v1.vx) / det,
		(l2.c * v1.vy - l1.c * v2.vy) / det,
	};
}
ld cross(const Pos& d1, const Pos& d2, const Pos& d3) { return (d2 - d1) / (d3 - d2); }
int ccw(const Pos& d1, const Pos& d2, const Pos& d3) { return sign(cross(d1, d2, d3)); }
ld dot(const Pos& d1, const Pos& d2, const Pos& d3) { return (d2 - d1) * (d3 - d2); }
ld area(const Polygon& H) {
	ld ret = 0;
	int sz = H.size();
	for (int i = 0; i < sz; i++) ret += H[i] / H[(i + 1) % sz];
	return ret;
}
bool norm(Polygon& H) {
	ld a = area(H);
	if (zero(a)) return 1;
	if (a < 0) std::reverse(H.begin(), H.end());
	return 0;
}
Polygon rotate_and_norm(Polygon B, const int& j0, const Polygon& A, const int& i0, const ld& t) {
	int sz = B.size();
	for (int j = 0; j < sz; j++) B[j] = B[j].rot(t);
	Pos v = A[i0] - B[j0];
	for (int j = 0; j < sz; j++) B[j] += v;
	return B;
}
struct Circle {
	Pos c;
	ld r;
	Circle(Pos C = Pos(0, 0), ld R = 0) : c(C), r(R) {}
	//bool operator == (const Circle& C) const { return c == C.c && std::abs(r - C.r) < TOL; }
	//bool operator != (const Circle& C) const { return !(*this == C); }
	bool operator > (const Pos& p) const { return r > (c - p).mag(); }
	bool operator >= (const Pos& p) const { return r + TOL > (c - p).mag(); }
	bool operator < (const Pos& p) const { return r < (c - p).mag(); }
} INVAL = { { 0, 0 }, -1 };
Circle enclose_circle(const Pos& u, const Pos& v) {
	Pos c = (u + v) * .5;
	return Circle(c, (c - u).mag());
}
Circle enclose_circle(const Pos& u, const Pos& v, const Pos& w) {
	Line l1 = rotate90(L(u, v), (u + v) * .5);
	Line l2 = rotate90(L(v, w), (v + w) * .5);
	if (zero(l1 / l2)) return { { 0, 0 }, -1 };
	Pos c = intersection(l1, l2);
	ld r = (c - u).mag();
	return Circle(c, r);
}
Circle minimum_enclose_circle(std::vector<Pos> P) {
	shuffle(P.begin(), P.end(), std::mt19937(0x14004));
	Circle mec = INVAL;
	int sz = P.size();
	for (int i = 0; i < sz; i++) {
		if (mec.r < -1 || mec < P[i]) {
			mec = Circle(P[i], 0);
			for (int j = 0; j <= i; j++) {
				if (mec < P[j]) {
					Circle ans = enclose_circle(P[i], P[j]);
					if (zero(mec.r)) { mec = ans; continue; }
					Circle l = INVAL, r = INVAL;
					for (int k = 0; k <= j; k++) {
						if (ans < P[k]) {
							int CCW = ccw(P[i], P[j], P[k]);
							Circle c = enclose_circle(P[i], P[j], P[k]);
							if (c.r < 0) continue;
							else if (CCW > 0 && (l.r < 0 || cross(P[i], P[j], c.c) > cross(P[i], P[j], l.c))) l = c;
							else if (CCW < 0 && (r.r < 0 || cross(P[i], P[j], c.c) < cross(P[i], P[j], r.c))) r = c;
						}
					}
					if (l.r < 0 && r.r < 0) mec = ans;
					else if (l.r < 0) mec = r;
					else if (r.r < 0) mec = l;
					else mec = l.r < r.r ? l : r;
				}
			}
		}
	}
	return mec;
}
Circle minimum_enclose_circle(Polygon A, int i, Polygon B, int j, ld d) {
	Polygon V;
	Pos v = (A[(i + 1) % A.size()] - B[(j + 1) % B.size()]).unit() * d;
	for (Pos& p : B) p += v;
	for (const Pos& p : A) V.push_back(p);
	for (const Pos& p : B) V.push_back(p);
	return minimum_enclose_circle(V);
}
ld ternary_search(const Polygon& A, const int& i, const Polygon& B, const int& j) {
	int a = A.size(), b = B.size();
	const Pos& pa = A[(i + 1) % a], & pb = B[(j + 1) % b];
	ld s = 0, e = (pa - pb).mag(), m1, m2, r1 = 0, r2 = 0;
	int cnt = 25; while (cnt--) {
		m1 = (s + s + e) / 3;
		m2 = (s + e + e) / 3;
		r1 = minimum_enclose_circle(A, i, B, j, m1).r;
		r2 = minimum_enclose_circle(A, i, B, j, m2).r;
		if (r1 > r2) s = m1;
		else e = m2;
	}
	return r2;
}
ld fit(const Polygon& P, const ld& r) {
	auto dist = [&](const Pos& s1, const Pos& s2, const Pos& c) -> ld {
		ld d = cross(s1, s2, c) / (s1 - s2).mag();
		return r + d;
		};
	int sz = P.size();
	ld ret = INF;
	for (int i = 0; i < sz; i++) {
		for (int j = i + 1; j < sz; j++) {
			ld tmp = INF;
			const Pos& p = P[i], & q = P[j];
			Pos mid = (p + q) * .5;
			Pos vec = p - mid;
			ld h = vec.mag();
			if (sign(h - r) > 0) continue;
			ld w = sqrt(r * r - h * h);
			Pos c1 = mid + ~vec.unit() * w;
			Pos c2 = mid - ~vec.unit() * w;
			for (const Pos& c : { c1, c2 }) {
				for (int k = 0; k < sz; k++) {
					const Pos& p0 = P[(k - 1 + sz) % sz], & p1 = P[k], & p2 = P[(k + 1) % sz];
					assert(ccw(p0, p1, p2) >= 0);
					if (k == i || k == j) continue;
					if (sign((P[k] - c).mag() - r) > 0) { tmp = INF; break; }
					if (ccw(p0, p1, c) < 0 && ccw(p1, p2, c) < 0 && dot(p0, p1, c) > 0 && dot(p2, p1, c) > 0) {
						tmp = std::min(tmp, r - (c - p1).mag());
					}
					else tmp = std::min({ tmp, dist(p0, p1, c), dist(p1, p2, c) });
				}
				ret = std::min(ret, tmp);
			}
		}
	}
	return ret;
}
bool fit(const Polygon& A, const Polygon& B, const ld& r) {
	ld da = fit(A, r), db = fit(B, r);
	return sign(r + r - (da + db)) >= 0 ? 1 : 0;
}
ld bi_search(const Polygon& A, const Polygon& B, ld s, ld e) {
	int cnt = 30; while (cnt--) {
		ld m = (s + e) * .5;
		if (fit(A, B, m)) e = m;
		else s = m;
	}
	return (s + e) * .5;
}
bool query() {
	std::cin >> N;
	if (!N) return 0;
	Polygon A(N);
	for (Pos& p : A) std::cin >> p;
	norm(A);
	std::cin >> M;
	Polygon B(M);
	for (Pos& p : B) std::cin >> p;
	norm(B);
	ld ret = INF, r1 = INF;
	ld ra = minimum_enclose_circle(A).r, rb = minimum_enclose_circle(B).r;
	for (int i = 0; i < N; i++) {
		Pos& I0 = A[i], & I1 = A[(i + 1) % N];
		for (int j = 0; j < M; j++) {
			Pos& J0 = B[j], & J1 = B[(j + 1) % M];
			ld t = rad(J0 - J1, I1 - I0);
			Polygon B2 = rotate_and_norm(B, j, A, i, t);
			r1 = std::min(r1, ternary_search(A, i, B2, j));
		}
	}
	ld r2 = bi_search(A, B, std::max(ra, rb), r1);
	ret = std::min({ ret, r1, r2 }) * 2;
	//ans.push_back(ret);
	std::cout << ret << "\n";
	return 1;
}
void solve() {
	std::cin.tie(0)->sync_with_stdio(0);
	std::cout.tie(0);
	std::cout << std::fixed;
	std::cout.precision(15);
	while (query());
	//for (const ld& ret : ans) std::cout << ret << "\n";
	return;
}
int main() { solve(); return 0; }//boj20231 Idealistic Canister
accuracy: 1
time_ms: 3950
memory_kb: 3852
final_rank: 6

code_snippet: #define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <algorithm>
#include <vector>
#include <cmath>
#include <cstring>
#include <cassert>
#include <random>
typedef long long ll;
//typedef long double ld;
typedef double ld;
typedef std::vector<ld> Vld;
const ld INF = 1e17;
const ld TOL = 1e-7;
const ld PI = acos(-1);
const int LEN = 1e3;
inline int sign(const ld& x) { return x < -TOL ? -1 : x > TOL; }
inline bool zero(const ld& x) { return !sign(x); }
inline bool eq(const ld& x, const ld& y) { return zero(x - y); }

Vld ans;
int N, M;
struct Pos {
	ld x, y;
	Pos(ld X = 0, ld Y = 0) : x(X), y(Y) {}
	bool operator == (const Pos& p) const { return zero(x - p.x) && zero(y - p.y); }
	bool operator != (const Pos& p) const { return !zero(x - p.x) || !zero(y - p.y); }
	bool operator < (const Pos& p) const { return zero(x - p.x) ? y < p.y : x < p.x; }
	bool operator <= (const Pos& p) const { return *this < p || *this == p; }
	Pos operator + (const Pos& p) const { return { x + p.x, y + p.y }; }
	Pos operator - (const Pos& p) const { return { x - p.x, y - p.y }; }
	Pos operator * (const ld& scalar) const { return { x * scalar, y * scalar }; }
	Pos operator / (const ld& scalar) const { return { x / scalar, y / scalar }; }
	ld operator * (const Pos& p) const { return x * p.x + y * p.y; }
	ld operator / (const Pos& p) const { return x * p.y - y * p.x; }
	Pos& operator += (const Pos& p) { x += p.x; y += p.y; return *this; }
	Pos& operator -= (const Pos& p) { x -= p.x; y -= p.y; return *this; }
	Pos& operator *= (const ld& scale) { x *= scale; y *= scale; return *this; }
	Pos& operator /= (const ld& scale) { x /= scale; y /= scale; return *this; }
	Pos operator - () const { return { -x, -y }; }
	Pos operator ~ () const { return { -y, x }; }
	Pos rot(ld the) const { return { x * cos(the) - y * sin(the), x * sin(the) + y * cos(the) }; }
	ld Euc() const { return x * x + y * y; }
	ld mag() const { return sqrt(Euc()); }
	Pos unit() const { return *this / mag(); }
	ld rad() const { return atan2(y, x); }
	friend ld rad(const Pos& p1, const Pos& p2) { return atan2l(p1 / p2, p1 * p2); }
	friend std::istream& operator >> (std::istream& is, Pos& p) { is >> p.x >> p.y; return is; }
	friend std::ostream& operator << (std::ostream& os, const Pos& p) { os << "(" << p.x << ", " << p.y << ")"; return os; }
}; const Pos O = Pos(0, 0);
typedef std::vector<Pos> Polygon;
struct Vec {
	ld vy, vx;
	Vec(ld Y = 0, ld X = 0) : vy(Y), vx(X) {}
	bool operator == (const Vec& v) const { return (zero(vy - v.vy) && zero(vx - v.vx)); }
	bool operator < (const Vec& v) const { return zero(vy - v.vy) ? vx < v.vx : vy < v.vy; }
	ld operator * (const Vec& v) const { return vy * v.vy + vx * v.vx; }
	ld operator / (const Vec& v) const { return vy * v.vx - vx * v.vy; }
	Vec operator ~ () const { return { -vx, vy }; }
}; const Vec Zero = { 0, 0 };
struct Line {//ax + by = c
	Vec s;
	ld c;
	Line(Vec V = Vec(0, 0), ld C = 0) : s(V), c(C) {}
	Line(Vec V = Vec(0, 0), Pos p = Pos(0, 0)) : s(V) { c = s.vy * p.x + s.vx * p.y; }
	Line(Pos ps = Pos(0, 0), Pos pe = Pos(0, 0)) {
		ld dy, dx;
		dy = pe.y - ps.y;
		dx = ps.x - pe.x;
		s = Vec(dy, dx);
		c = dy * ps.x + dx * ps.y;
	}
	ld operator / (const Line& l) const { return s / l.s; }
	ld operator * (const Line& l) const { return s * l.s; }
};
Line L(const Pos& s, const Pos& e) { return Line(s, e); }
Line rotate90(const Line& l, const Pos& p) { return Line(~l.s, p); }
Pos intersection(const Line& l1, const Line& l2) {
	Vec v1 = l1.s, v2 = l2.s;
	ld det = v1 / v2;
	return {
		(l1.c * v2.vx - l2.c * v1.vx) / det,
		(l2.c * v1.vy - l1.c * v2.vy) / det,
	};
}
ld cross(const Pos& d1, const Pos& d2, const Pos& d3) { return (d2 - d1) / (d3 - d2); }
int ccw(const Pos& d1, const Pos& d2, const Pos& d3) { return sign(cross(d1, d2, d3)); }
ld dot(const Pos& d1, const Pos& d2, const Pos& d3) { return (d2 - d1) * (d3 - d2); }
ld area(const Polygon& H) {
	ld ret = 0;
	int sz = H.size();
	for (int i = 0; i < sz; i++) ret += H[i] / H[(i + 1) % sz];
	return ret;
}
bool norm(Polygon& H) {
	ld a = area(H);
	if (zero(a)) return 1;
	if (a < 0) std::reverse(H.begin(), H.end());
	return 0;
}
Polygon rotate_and_norm(Polygon B, const int& j0, const Polygon& A, const int& i0, const ld& t) {
	int sz = B.size();
	for (int j = 0; j < sz; j++) B[j] = B[j].rot(t);
	Pos v = A[i0] - B[j0];
	for (int j = 0; j < sz; j++) B[j] += v;
	return B;
}
struct Circle {
	Pos c;
	ld r;
	Circle(Pos C = Pos(0, 0), ld R = 0) : c(C), r(R) {}
	bool operator == (const Circle& C) const { return c == C.c && std::abs(r - C.r) < TOL; }
	bool operator != (const Circle& C) const { return !(*this == C); }
	bool operator > (const Pos& p) const { return r > (c - p).mag(); }
	bool operator >= (const Pos& p) const { return r + TOL > (c - p).mag(); }
	bool operator < (const Pos& p) const { return r < (c - p).mag(); }
} INVAL = { { 0, 0 }, -1 };
Circle enclose_circle(const Pos& u, const Pos& v) {
	Pos c = (u + v) * .5;
	return Circle(c, (c - u).mag());
}
Circle enclose_circle(const Pos& u, const Pos& v, const Pos& w) {
	Line l1 = rotate90(L(u, v), (u + v) * .5);
	Line l2 = rotate90(L(v, w), (v + w) * .5);
	if (zero(l1 / l2)) return { { 0, 0 }, -1 };
	Pos c = intersection(l1, l2);
	ld r = (c - u).mag();
	return Circle(c, r);
}
Circle minimum_enclose_circle(std::vector<Pos> P) {
	shuffle(P.begin(), P.end(), std::mt19937(0x14004));
	Circle mec = INVAL;
	int sz = P.size();
	for (int i = 0; i < sz; i++) {
		if (mec.r < -1 || mec < P[i]) {
			mec = Circle(P[i], 0);
			for (int j = 0; j <= i; j++) {
				if (mec < P[j]) {
					Circle ans = enclose_circle(P[i], P[j]);
					if (zero(mec.r)) { mec = ans; continue; }
					Circle l = INVAL, r = INVAL;
					for (int k = 0; k <= j; k++) {
						if (ans < P[k]) {
							int CCW = ccw(P[i], P[j], P[k]);
							Circle c = enclose_circle(P[i], P[j], P[k]);
							if (c.r < 0) continue;
							else if (CCW > 0 && (l.r < 0 || cross(P[i], P[j], c.c) > cross(P[i], P[j], l.c))) l = c;
							else if (CCW < 0 && (r.r < 0 || cross(P[i], P[j], c.c) < cross(P[i], P[j], r.c))) r = c;
						}
					}
					if (l.r < 0 && r.r < 0) mec = ans;
					else if (l.r < 0) mec = r;
					else if (r.r < 0) mec = l;
					else mec = l.r < r.r ? l : r;
				}
			}
		}
	}
	return mec;
}
Circle minimum_enclose_circle(Polygon A, int i, Polygon B, int j, ld d) {
	Polygon V;
	Pos v = (A[(i + 1) % A.size()] - B[(j + 1) % B.size()]).unit() * d;
	for (Pos& p : B) p += v;
	for (const Pos& p : A) V.push_back(p);
	for (const Pos& p : B) V.push_back(p);
	return minimum_enclose_circle(V);
}
ld ternary_search(const Polygon& A, const int& i, const Polygon& B, const int& j) {
	int a = A.size(), b = B.size();
	const Pos& pa = A[(i + 1) % a], & pb = B[(j + 1) % b];
	ld s = 0, e = (pa - pb).mag(), m1, m2, r1 = 0, r2 = 0;
	int cnt = 25; while (cnt--) {
		m1 = (s + s + e) / 3;
		m2 = (s + e + e) / 3;
		r1 = minimum_enclose_circle(A, i, B, j, m1).r;
		r2 = minimum_enclose_circle(A, i, B, j, m2).r;
		if (r1 > r2) s = m1;
		else e = m2;
	}
	return r2;
}
ld fit(const Polygon& P, const ld& r) {
	auto dist = [&](const Pos& s1, const Pos& s2, const Pos& c) -> ld {
		ld d = cross(s1, s2, c) / (s1 - s2).mag();
		return r + d;
		};
	int sz = P.size();
	ld ret = INF;
	for (int i = 0; i < sz; i++) {
		for (int j = i + 1; j < sz; j++) {
			ld tmp = INF;
			const Pos& p = P[i], & q = P[j];
			Pos mid = (p + q) * .5;
			Pos vec = p - mid;
			ld h = vec.mag();
			if (sign(h - r) > 0) continue;
			ld w = sqrt(r * r - h * h);
			Pos c1 = mid + ~vec.unit() * w;
			Pos c2 = mid - ~vec.unit() * w;
			for (const Pos& c : { c1, c2 }) {
				for (int k = 0; k < sz; k++) {
					const Pos& p0 = P[(k - 1 + sz) % sz], & p1 = P[k], & p2 = P[(k + 1) % sz];
					assert(ccw(p0, p1, p2) >= 0);
					if (k == i || k == j) continue;
					if (sign((P[k] - c).mag() - r) > 0) { tmp = INF; break; }
					if (ccw(p0, p1, c) < 0 && ccw(p1, p2, c) < 0 && dot(p0, p1, c) > 0 && dot(p2, p1, c) > 0) {
						tmp = std::min(tmp, r - (c - p1).mag());
					}
					else tmp = std::min({ tmp, dist(p0, p1, c), dist(p1, p2, c) });
				}
				ret = std::min(ret, tmp);
			}
		}
	}
	return ret;
}
bool fit(const Polygon& A, const Polygon& B, const ld& r) {
	ld da = fit(A, r), db = fit(B, r);
	return sign(r + r - (da + db)) >= 0 ? 1 : 0;
}
ld bi_search(const Polygon& A, const Polygon& B, ld s, ld e) {
	int cnt = 30; while (cnt--) {
		ld m = (s + e) * .5;
		if (fit(A, B, m)) e = m;
		else s = m;
	}
	return (s + e) * .5;
}
bool query() {
	std::cin >> N;
	if (!N) return 0;
	Polygon A(N);
	for (Pos& p : A) std::cin >> p;
	norm(A);
	std::cin >> M;
	Polygon B(M);
	for (Pos& p : B) std::cin >> p;
	norm(B);
	ld ret = INF;
	ld r1 = INF;
	ld ra = minimum_enclose_circle(A).r, rb = minimum_enclose_circle(B).r;
	for (int i = 0; i < N; i++) {
		Pos& I0 = A[i], & I1 = A[(i + 1) % N];
		for (int j = 0; j < M; j++) {
			Pos& J0 = B[j], & J1 = B[(j + 1) % M];
			ld t = rad(J0 - J1, I1 - I0);
			Polygon B2 = rotate_and_norm(B, j, A, i, t);
			r1 = std::min(r1, ternary_search(A, i, B2, j));
		}
	}
	ld r2 = bi_search(A, B, std::max(ra, rb), r1);
	ret = std::min({ ret, r1, r2 }) * 2;
	ans.push_back(ret);
	return 1;
}
void solve() {
	std::cin.tie(0)->sync_with_stdio(0);
	std::cout.tie(0);
	std::cout << std::fixed;
	std::cout.precision(15);
	while (query());
	for (const ld& ret : ans) std::cout << ret << "\n";
	return;
}
int main() { solve(); return 0; }//boj20231 Idealistic Canister
accuracy: 1
time_ms: 3750
memory_kb: 3928
final_rank: 5

code_snippet: #define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <algorithm>
#include <vector>
#include <cmath>
#include <cstring>
#include <cassert>
#include <random>
typedef long long ll;
//typedef long double ld;
typedef double ld;
typedef std::vector<ld> Vld;
const ld INF = 1e17;
const ld TOL = 1e-7;
const ld PI = acos(-1);
const int LEN = 1e3;
inline int sign(const ld& x) { return x < -TOL ? -1 : x > TOL; }
inline bool zero(const ld& x) { return !sign(x); }
inline bool eq(const ld& x, const ld& y) { return zero(x - y); }

Vld ans;
int N, M;
struct Pos {
	ld x, y;
	Pos(ld X = 0, ld Y = 0) : x(X), y(Y) {}
	bool operator == (const Pos& p) const { return zero(x - p.x) && zero(y - p.y); }
	bool operator != (const Pos& p) const { return !zero(x - p.x) || !zero(y - p.y); }
	bool operator < (const Pos& p) const { return zero(x - p.x) ? y < p.y : x < p.x; }
	bool operator <= (const Pos& p) const { return *this < p || *this == p; }
	Pos operator + (const Pos& p) const { return { x + p.x, y + p.y }; }
	Pos operator - (const Pos& p) const { return { x - p.x, y - p.y }; }
	Pos operator * (const ld& scalar) const { return { x * scalar, y * scalar }; }
	Pos operator / (const ld& scalar) const { return { x / scalar, y / scalar }; }
	ld operator * (const Pos& p) const { return x * p.x + y * p.y; }
	ld operator / (const Pos& p) const { return x * p.y - y * p.x; }
	Pos& operator += (const Pos& p) { x += p.x; y += p.y; return *this; }
	Pos& operator -= (const Pos& p) { x -= p.x; y -= p.y; return *this; }
	Pos& operator *= (const ld& scale) { x *= scale; y *= scale; return *this; }
	Pos& operator /= (const ld& scale) { x /= scale; y /= scale; return *this; }
	Pos operator - () const { return { -x, -y }; }
	Pos operator ~ () const { return { -y, x }; }
	Pos rot(ld the) const { return { x * cos(the) - y * sin(the), x * sin(the) + y * cos(the) }; }
	ld Euc() const { return x * x + y * y; }
	ld mag() const { return sqrt(Euc()); }
	Pos unit() const { return *this / mag(); }
	ld rad() const { return atan2(y, x); }
	friend ld rad(const Pos& p1, const Pos& p2) { return atan2l(p1 / p2, p1 * p2); }
	friend std::istream& operator >> (std::istream& is, Pos& p) { is >> p.x >> p.y; return is; }
	friend std::ostream& operator << (std::ostream& os, const Pos& p) { os << "(" << p.x << ", " << p.y << ")"; return os; }
}; const Pos O = Pos(0, 0);
typedef std::vector<Pos> Polygon;
struct Vec {
	ld vy, vx;
	Vec(ld Y = 0, ld X = 0) : vy(Y), vx(X) {}
	bool operator == (const Vec& v) const { return (zero(vy - v.vy) && zero(vx - v.vx)); }
	bool operator < (const Vec& v) const { return zero(vy - v.vy) ? vx < v.vx : vy < v.vy; }
	ld operator * (const Vec& v) const { return vy * v.vy + vx * v.vx; }
	ld operator / (const Vec& v) const { return vy * v.vx - vx * v.vy; }
	Vec operator ~ () const { return { -vx, vy }; }
}; const Vec Zero = { 0, 0 };
struct Line {//ax + by = c
	Vec s;
	ld c;
	Line(Vec V = Vec(0, 0), ld C = 0) : s(V), c(C) {}
	Line(Vec V = Vec(0, 0), Pos p = Pos(0, 0)) : s(V) { c = s.vy * p.x + s.vx * p.y; }
	Line(Pos ps = Pos(0, 0), Pos pe = Pos(0, 0)) {
		ld dy, dx;
		dy = pe.y - ps.y;
		dx = ps.x - pe.x;
		s = Vec(dy, dx);
		c = dy * ps.x + dx * ps.y;
	}
	ld operator / (const Line& l) const { return s / l.s; }
	ld operator * (const Line& l) const { return s * l.s; }
};
Line L(const Pos& s, const Pos& e) { return Line(s, e); }
Line rotate90(const Line& l, const Pos& p) { return Line(~l.s, p); }
Pos intersection(const Line& l1, const Line& l2) {
	Vec v1 = l1.s, v2 = l2.s;
	ld det = v1 / v2;
	return {
		(l1.c * v2.vx - l2.c * v1.vx) / det,
		(l2.c * v1.vy - l1.c * v2.vy) / det,
	};
}
ld cross(const Pos& d1, const Pos& d2, const Pos& d3) { return (d2 - d1) / (d3 - d2); }
int ccw(const Pos& d1, const Pos& d2, const Pos& d3) { return sign(cross(d1, d2, d3)); }
ld dot(const Pos& d1, const Pos& d2, const Pos& d3) { return (d2 - d1) * (d3 - d2); }
ld area(const Polygon& H) {
	ld ret = 0;
	int sz = H.size();
	for (int i = 0; i < sz; i++) ret += H[i] / H[(i + 1) % sz];
	return ret;
}
bool norm(Polygon& H) {
	ld a = area(H);
	if (zero(a)) return 1;
	if (a < 0) std::reverse(H.begin(), H.end());
	return 0;
}
Polygon rotate_and_norm(Polygon B, const int& j0, const Polygon& A, const int& i0, const ld& t) {
	int sz = B.size();
	for (int j = 0; j < sz; j++) B[j] = B[j].rot(t);
	Pos v = A[i0] - B[j0];
	for (int j = 0; j < sz; j++) B[j] += v;
	return B;
}
struct Circle {
	Pos c;
	ld r;
	Circle(Pos C = Pos(0, 0), ld R = 0) : c(C), r(R) {}
	bool operator == (const Circle& C) const { return c == C.c && std::abs(r - C.r) < TOL; }
	bool operator != (const Circle& C) const { return !(*this == C); }
	bool operator > (const Pos& p) const { return r > (c - p).mag(); }
	bool operator >= (const Pos& p) const { return r + TOL > (c - p).mag(); }
	bool operator < (const Pos& p) const { return r < (c - p).mag(); }
} INVAL = { { 0, 0 }, -1 };
Circle enclose_circle(const Pos& u, const Pos& v) {
	Pos c = (u + v) * .5;
	return Circle(c, (c - u).mag());
}
Circle enclose_circle(const Pos& u, const Pos& v, const Pos& w) {
	Line l1 = rotate90(L(u, v), (u + v) * .5);
	Line l2 = rotate90(L(v, w), (v + w) * .5);
	if (zero(l1 / l2)) return { { 0, 0 }, -1 };
	Pos c = intersection(l1, l2);
	ld r = (c - u).mag();
	return Circle(c, r);
}
Circle minimum_enclose_circle(std::vector<Pos> P) {
	shuffle(P.begin(), P.end(), std::mt19937(0x14004));
	Circle mec = INVAL;
	int sz = P.size();
	for (int i = 0; i < sz; i++) {
		if (mec.r < -1 || mec < P[i]) {
			mec = Circle(P[i], 0);
			for (int j = 0; j <= i; j++) {
				if (mec < P[j]) {
					Circle ans = enclose_circle(P[i], P[j]);
					if (zero(mec.r)) { mec = ans; continue; }
					Circle l = INVAL, r = INVAL;
					for (int k = 0; k <= j; k++) {
						if (ans < P[k]) {
							int CCW = ccw(P[i], P[j], P[k]);
							Circle c = enclose_circle(P[i], P[j], P[k]);
							if (c.r < 0) continue;
							else if (CCW > 0 && (l.r < 0 || cross(P[i], P[j], c.c) > cross(P[i], P[j], l.c))) l = c;
							else if (CCW < 0 && (r.r < 0 || cross(P[i], P[j], c.c) < cross(P[i], P[j], r.c))) r = c;
						}
					}
					if (l.r < 0 && r.r < 0) mec = ans;
					else if (l.r < 0) mec = r;
					else if (r.r < 0) mec = l;
					else mec = l.r < r.r ? l : r;
				}
			}
		}
	}
	return mec;
}
Circle minimum_enclose_circle(Polygon A, int i, Polygon B, int j, ld d) {
	Polygon V;
	Pos v = (A[(i + 1) % A.size()] - B[(j + 1) % B.size()]).unit() * d;
	for (Pos& p : B) p += v;
	for (const Pos& p : A) V.push_back(p);
	for (const Pos& p : B) V.push_back(p);
	return minimum_enclose_circle(V);
}
ld ternary_search(const Polygon& A, const int& i, const Polygon& B, const int& j) {
	int a = A.size(), b = B.size();
	const Pos& pa = A[(i + 1) % a], & pb = B[(j + 1) % b];
	ld s = 0, e = (pa - pb).mag(), m1, m2, r1 = 0, r2 = 0;
	int cnt = 30; while (cnt--) {
		m1 = (s + s + e) / 3;
		m2 = (s + e + e) / 3;
		r1 = minimum_enclose_circle(A, i, B, j, m1).r;
		r2 = minimum_enclose_circle(A, i, B, j, m2).r;
		if (r1 > r2) s = m1;
		else e = m2;
	}
	return r2;
}
ld fit(const Polygon& P, const ld& r) {
	auto dist = [&](const Pos& s1, const Pos& s2, const Pos& c) -> ld {
		ld d = cross(s1, s2, c) / (s1 - s2).mag();
		return r + d;
		};
	int sz = P.size();
	ld ret = INF;
	for (int i = 0; i < sz; i++) {
		for (int j = i + 1; j < sz; j++) {
			ld tmp = INF;
			const Pos& p = P[i], & q = P[j];
			Pos mid = (p + q) * .5;
			Pos vec = p - mid;
			ld h = vec.mag();
			if (sign(h - r) > 0) continue;
			ld w = sqrt(r * r - h * h);
			Pos c1 = mid + ~vec.unit() * w;
			Pos c2 = mid - ~vec.unit() * w;
			for (const Pos& c : { c1, c2 }) {
				for (int k = 0; k < sz; k++) {
					const Pos& p0 = P[(k - 1 + sz) % sz], & p1 = P[k], & p2 = P[(k + 1) % sz];
					assert(ccw(p0, p1, p2) >= 0);
					if (k == i || k == j) continue;
					if (sign((P[k] - c).mag() - r) > 0) { tmp = INF; break; }
					if (ccw(p0, p1, c) < 0 && ccw(p1, p2, c) < 0 && dot(p0, p1, c) > 0 && dot(p2, p1, c) > 0) {
						tmp = std::min(tmp, r - (c - p1).mag());
					}
					else tmp = std::min({ tmp, dist(p0, p1, c), dist(p1, p2, c) });
				}
				ret = std::min(ret, tmp);
			}
		}
	}
	return ret;
}
bool fit(const Polygon& A, const Polygon& B, const ld& r) {
	ld da = fit(A, r), db = fit(B, r);
	return sign(r + r - (da + db)) >= 0 ? 1 : 0;
}
ld bi_search(const Polygon& A, const Polygon& B, ld s, ld e) {
	int cnt = 30; while (cnt--) {
		ld m = (s + e) * .5;
		if (fit(A, B, m)) e = m;
		else s = m;
	}
	return (s + e) * .5;
}
bool query() {
	std::cin >> N;
	if (!N) return 0;
	Polygon A(N);
	for (Pos& p : A) std::cin >> p;
	norm(A);
	std::cin >> M;
	Polygon B(M);
	for (Pos& p : B) std::cin >> p;
	norm(B);
	ld ret = INF;
	ld r1 = INF;
	ld ra = minimum_enclose_circle(A).r, rb = minimum_enclose_circle(B).r;
	for (int i = 0; i < N; i++) {
		Pos& I0 = A[i], & I1 = A[(i + 1) % N];
		for (int j = 0; j < M; j++) {
			Pos& J0 = B[j], & J1 = B[(j + 1) % M];
			ld t = rad(J0 - J1, I1 - I0);
			Polygon B2 = rotate_and_norm(B, j, A, i, t);
			r1 = std::min(r1, ternary_search(A, i, B2, j));
		}
	}
	ld r2 = bi_search(A, B, std::max(ra, rb), r1);
	ret = std::min({ ret, r1, r2 }) * 2;
	ans.push_back(ret);
	return 1;
}
void solve() {
	std::cin.tie(0)->sync_with_stdio(0);
	std::cout.tie(0);
	std::cout << std::fixed;
	std::cout.precision(15);
	while (query());
	for (const ld& ret : ans) std::cout << ret << "\n";
	return;
}
int main() { solve(); return 0; }//boj20231 Idealistic Canister
accuracy: 1
time_ms: 4470
memory_kb: 3860
final_rank: 7

code_snippet: #define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <algorithm>
#include <vector>
#include <cmath>
#include <cstring>
#include <cassert>
#include <random>
typedef long long ll;
//typedef long double ld;
typedef double ld;
typedef std::vector<ld> Vld;
const ld INF = 1e17;
const ld TOL = 1e-7;
const ld PI = acos(-1);
const int LEN = 1e3;
inline int sign(const ld& x) { return x < -TOL ? -1 : x > TOL; }
inline bool zero(const ld& x) { return !sign(x); }
inline bool eq(const ld& x, const ld& y) { return zero(x - y); }

Vld ans;
int N, M;
struct Pos {
	ld x, y;
	Pos(ld X = 0, ld Y = 0) : x(X), y(Y) {}
	bool operator == (const Pos& p) const { return zero(x - p.x) && zero(y - p.y); }
	bool operator != (const Pos& p) const { return !zero(x - p.x) || !zero(y - p.y); }
	bool operator < (const Pos& p) const { return zero(x - p.x) ? y < p.y : x < p.x; }
	bool operator <= (const Pos& p) const { return *this < p || *this == p; }
	Pos operator + (const Pos& p) const { return { x + p.x, y + p.y }; }
	Pos operator - (const Pos& p) const { return { x - p.x, y - p.y }; }
	Pos operator * (const ld& scalar) const { return { x * scalar, y * scalar }; }
	Pos operator / (const ld& scalar) const { return { x / scalar, y / scalar }; }
	ld operator * (const Pos& p) const { return x * p.x + y * p.y; }
	ld operator / (const Pos& p) const { return x * p.y - y * p.x; }
	Pos& operator += (const Pos& p) { x += p.x; y += p.y; return *this; }
	Pos& operator -= (const Pos& p) { x -= p.x; y -= p.y; return *this; }
	Pos& operator *= (const ld& scale) { x *= scale; y *= scale; return *this; }
	Pos& operator /= (const ld& scale) { x /= scale; y /= scale; return *this; }
	Pos operator - () const { return { -x, -y }; }
	Pos operator ~ () const { return { -y, x }; }
	Pos rot(ld the) const { return { x * cos(the) - y * sin(the), x * sin(the) + y * cos(the) }; }
	ld Euc() const { return x * x + y * y; }
	ld mag() const { return sqrt(Euc()); }
	Pos unit() const { return *this / mag(); }
	ld rad() const { return atan2(y, x); }
	friend ld rad(const Pos& p1, const Pos& p2) { return atan2l(p1 / p2, p1 * p2); }
	friend std::istream& operator >> (std::istream& is, Pos& p) { is >> p.x >> p.y; return is; }
	friend std::ostream& operator << (std::ostream& os, const Pos& p) { os << "(" << p.x << ", " << p.y << ")"; return os; }
}; const Pos O = Pos(0, 0);
typedef std::vector<Pos> Polygon;
struct Vec {
	ld vy, vx;
	Vec(ld Y = 0, ld X = 0) : vy(Y), vx(X) {}
	bool operator == (const Vec& v) const { return (zero(vy - v.vy) && zero(vx - v.vx)); }
	bool operator < (const Vec& v) const { return zero(vy - v.vy) ? vx < v.vx : vy < v.vy; }
	ld operator * (const Vec& v) const { return vy * v.vy + vx * v.vx; }
	ld operator / (const Vec& v) const { return vy * v.vx - vx * v.vy; }
	Vec operator ~ () const { return { -vx, vy }; }
}; const Vec Zero = { 0, 0 };
struct Line {//ax + by = c
	Vec s;
	ld c;
	Line(Vec V = Vec(0, 0), ld C = 0) : s(V), c(C) {}
	Line(Vec V = Vec(0, 0), Pos p = Pos(0, 0)) : s(V) { c = s.vy * p.x + s.vx * p.y; }
	Line(Pos ps = Pos(0, 0), Pos pe = Pos(0, 0)) {
		ld dy, dx;
		dy = pe.y - ps.y;
		dx = ps.x - pe.x;
		s = Vec(dy, dx);
		c = dy * ps.x + dx * ps.y;
	}
	ld operator / (const Line& l) const { return s / l.s; }
	ld operator * (const Line& l) const { return s * l.s; }
};
Line L(const Pos& s, const Pos& e) { return Line(s, e); }
Line rotate90(const Line& l, const Pos& p) { return Line(~l.s, p); }
Pos intersection(const Line& l1, const Line& l2) {
	Vec v1 = l1.s, v2 = l2.s;
	ld det = v1 / v2;
	return {
		(l1.c * v2.vx - l2.c * v1.vx) / det,
		(l2.c * v1.vy - l1.c * v2.vy) / det,
	};
}
ld cross(const Pos& d1, const Pos& d2, const Pos& d3) { return (d2 - d1) / (d3 - d2); }
int ccw(const Pos& d1, const Pos& d2, const Pos& d3) { return sign(cross(d1, d2, d3)); }
ld dot(const Pos& d1, const Pos& d2, const Pos& d3) { return (d2 - d1) * (d3 - d2); }
ld area(const Polygon& H) {
	ld ret = 0;
	int sz = H.size();
	for (int i = 0; i < sz; i++) ret += H[i] / H[(i + 1) % sz];
	return ret;
}
bool norm(Polygon& H) {
	ld a = area(H);
	if (zero(a)) return 1;
	if (a < 0) std::reverse(H.begin(), H.end());
	return 0;
}
Polygon rotate_and_norm(Polygon B, const int& j0, const Polygon& A, const int& i0, const ld& t) {
	int sz = B.size();
	for (int j = 0; j < sz; j++) B[j] = B[j].rot(t);
	Pos v = A[i0] - B[j0];
	for (int j = 0; j < sz; j++) B[j] += v;
	return B;
}
struct Circle {
	Pos c;
	ld r;
	Circle(Pos C = Pos(0, 0), ld R = 0) : c(C), r(R) {}
	bool operator == (const Circle& C) const { return c == C.c && std::abs(r - C.r) < TOL; }
	bool operator != (const Circle& C) const { return !(*this == C); }
	bool operator > (const Pos& p) const { return r > (c - p).mag(); }
	bool operator >= (const Pos& p) const { return r + TOL > (c - p).mag(); }
	bool operator < (const Pos& p) const { return r < (c - p).mag(); }
} INVAL = { { 0, 0 }, -1 };
Circle enclose_circle(const Pos& u, const Pos& v) {
	Pos c = (u + v) * .5;
	return Circle(c, (c - u).mag());
}
Circle enclose_circle(const Pos& u, const Pos& v, const Pos& w) {
	Line l1 = rotate90(L(u, v), (u + v) * .5);
	Line l2 = rotate90(L(v, w), (v + w) * .5);
	if (zero(l1 / l2)) return { { 0, 0 }, -1 };
	Pos c = intersection(l1, l2);
	ld r = (c - u).mag();
	return Circle(c, r);
}
Circle minimum_enclose_circle(std::vector<Pos> P) {
	shuffle(P.begin(), P.end(), std::mt19937(0x14004));
	Circle mec = INVAL;
	int sz = P.size();
	for (int i = 0; i < sz; i++) {
		if (mec.r < -1 || mec < P[i]) {
			mec = Circle(P[i], 0);
			for (int j = 0; j <= i; j++) {
				if (mec < P[j]) {
					Circle ans = enclose_circle(P[i], P[j]);
					if (zero(mec.r)) { mec = ans; continue; }
					Circle l = INVAL, r = INVAL;
					for (int k = 0; k <= j; k++) {
						if (ans < P[k]) {
							int CCW = ccw(P[i], P[j], P[k]);
							Circle c = enclose_circle(P[i], P[j], P[k]);
							if (c.r < 0) continue;
							else if (CCW > 0 && (l.r < 0 || cross(P[i], P[j], c.c) > cross(P[i], P[j], l.c))) l = c;
							else if (CCW < 0 && (r.r < 0 || cross(P[i], P[j], c.c) < cross(P[i], P[j], r.c))) r = c;
						}
					}
					if (l.r < 0 && r.r < 0) mec = ans;
					else if (l.r < 0) mec = r;
					else if (r.r < 0) mec = l;
					else mec = l.r < r.r ? l : r;
				}
			}
		}
	}
	return mec;
}
Circle minimum_enclose_circle(Polygon A, int i, Polygon B, int j, ld d) {
	Polygon V;
	Pos v = (A[(i + 1) % A.size()] - B[(j + 1) % B.size()]).unit() * d;
	for (Pos& p : B) p += v;
	for (const Pos& p : A) V.push_back(p);
	for (const Pos& p : B) V.push_back(p);
	return minimum_enclose_circle(V);
}
ld ternary_search(const Polygon& A, const int& i, const Polygon& B, const int& j) {
	int a = A.size(), b = B.size();
	const Pos& pa = A[(i + 1) % a], & pb = B[(j + 1) % b];
	ld s = 0, e = (pa - pb).mag(), m1, m2, r1 = 0, r2 = 0;
	int cnt = 50; while (cnt--) {
		m1 = (s + s + e) / 3;
		m2 = (s + e + e) / 3;
		r1 = minimum_enclose_circle(A, i, B, j, m1).r;
		r2 = minimum_enclose_circle(A, i, B, j, m2).r;
		if (r1 > r2) s = m1;
		else e = m2;
	}
	return r2;
}
ld fit(const Polygon& P, const ld& r) {
	auto dist = [&](const Pos& s1, const Pos& s2, const Pos& c) -> ld {
		ld d = cross(s1, s2, c) / (s1 - s2).mag();
		return r + d;
		};
	int sz = P.size();
	ld ret = INF;
	for (int i = 0; i < sz; i++) {
		for (int j = i + 1; j < sz; j++) {
			ld tmp = INF;
			const Pos& p = P[i], & q = P[j];
			Pos mid = (p + q) * .5;
			Pos vec = p - mid;
			ld h = vec.mag();
			if (sign(h - r) > 0) continue;
			ld w = sqrt(r * r - h * h);
			Pos c1 = mid + ~vec.unit() * w;
			Pos c2 = mid - ~vec.unit() * w;
			for (const Pos& c : { c1, c2 }) {
				for (int k = 0; k < sz; k++) {
					const Pos& p0 = P[(k - 1 + sz) % sz], & p1 = P[k], & p2 = P[(k + 1) % sz];
					assert(ccw(p0, p1, p2) >= 0);
					if (k == i || k == j) continue;
					if (sign((P[k] - c).mag() - r) > 0) { tmp = INF; break; }
					if (ccw(p0, p1, c) < 0 && ccw(p1, p2, c) < 0 && dot(p0, p1, c) > 0 && dot(p2, p1, c) > 0) {
						tmp = std::min(tmp, r - (c - p1).mag());
					}
					else tmp = std::min({ tmp, dist(p0, p1, c), dist(p1, p2, c) });
				}
				ret = std::min(ret, tmp);
			}
		}
	}
	return ret;
}
bool fit(const Polygon& A, const Polygon& B, const ld& r) {
	ld da = fit(A, r), db = fit(B, r);
	return sign(r + r - (da + db)) >= 0 ? 1 : 0;
}
ld bi_search(const Polygon& A, const Polygon& B, ld s, ld e) {
	int cnt = 30; while (cnt--) {
		ld m = (s + e) * .5;
		if (fit(A, B, m)) e = m;
		else s = m;
	}
	return (s + e) * .5;
}
bool query() {
	std::cin >> N;
	if (!N) return 0;
	Polygon A(N);
	for (Pos& p : A) std::cin >> p;
	norm(A);
	std::cin >> M;
	Polygon B(M);
	for (Pos& p : B) std::cin >> p;
	norm(B);
	ld ret = INF;
	ld r1 = INF;
	ld ra = minimum_enclose_circle(A).r, rb = minimum_enclose_circle(B).r;
	for (int i = 0; i < N; i++) {
		Pos& I0 = A[i], & I1 = A[(i + 1) % N];
		for (int j = 0; j < M; j++) {
			Pos& J0 = B[j], & J1 = B[(j + 1) % M];
			ld t = rad(J0 - J1, I1 - I0);
			Polygon B2 = rotate_and_norm(B, j, A, i, t);
			r1 = std::min(r1, ternary_search(A, i, B2, j));
		}
	}
	ld r2 = bi_search(A, B, std::max(ra, rb), r1);
	ret = std::min({ ret, r1, r2 }) * 2;
	ans.push_back(ret);
	return 1;
}
void solve() {
	std::cin.tie(0)->sync_with_stdio(0);
	std::cout.tie(0);
	std::cout << std::fixed;
	std::cout.precision(15);
	while (query());
	for (const ld& ret : ans) std::cout << ret << "\n";
	return;
}
int main() { solve(); return 0; }//boj20231 Idealistic Canister
accuracy: 1
time_ms: 7360
memory_kb: 3960
final_rank: 11

code_snippet: #define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <algorithm>
#include <vector>
#include <cmath>
#include <cstring>
#include <cassert>
#include <random>
#include <array>
#include <tuple>
typedef long long ll;
//typedef long double ld;
typedef double ld;
typedef std::pair<int, int> pi;
typedef std::vector<ld> Vld;
const ld INF = 1e17;
const ld TOL = 1e-7;
const ld PI = acos(-1);
const int LEN = 1e3;
inline int sign(const ld& x) { return x < -TOL ? -1 : x > TOL; }
inline bool zero(const ld& x) { return !sign(x); }
inline bool eq(const ld& x, const ld& y) { return zero(x - y); }

Vld ans;
int N, M;
struct Pos {
	ld x, y;
	Pos(ld X = 0, ld Y = 0) : x(X), y(Y) {}
	bool operator == (const Pos& p) const { return zero(x - p.x) && zero(y - p.y); }
	bool operator != (const Pos& p) const { return !zero(x - p.x) || !zero(y - p.y); }
	bool operator < (const Pos& p) const { return zero(x - p.x) ? y < p.y : x < p.x; }
	//bool operator < (const Pos& r) const { return x == r.x ? y == r.y ? d < r.d : y < r.y : x < r.x; }
	//bool operator < (const Pos& r) const { return zero(x - r.x) ? zero(y - r.y) ? d < r.d : y < r.y : x < r.x; }
	bool operator <= (const Pos& p) const { return *this < p || *this == p; }
	Pos operator + (const Pos& p) const { return { x + p.x, y + p.y }; }
	Pos operator - (const Pos& p) const { return { x - p.x, y - p.y }; }
	Pos operator * (const ld& scalar) const { return { x * scalar, y * scalar }; }
	Pos operator / (const ld& scalar) const { return { x / scalar, y / scalar }; }
	ld operator * (const Pos& p) const { return x * p.x + y * p.y; }
	ld operator / (const Pos& p) const { return x * p.y - y * p.x; }
	Pos operator ^ (const Pos& p) const { return { x * p.x, y * p.y }; }
	Pos& operator += (const Pos& p) { x += p.x; y += p.y; return *this; }
	Pos& operator -= (const Pos& p) { x -= p.x; y -= p.y; return *this; }
	Pos& operator *= (const ld& scale) { x *= scale; y *= scale; return *this; }
	Pos& operator /= (const ld& scale) { x /= scale; y /= scale; return *this; }
	Pos operator - () const { return { -x, -y }; }
	Pos operator ~ () const { return { -y, x }; }
	Pos operator ! () const { return { y, x }; }
	ld xy() const { return x * y; }
	Pos rot(ld the) const { return { x * cos(the) - y * sin(the), x * sin(the) + y * cos(the) }; }
	ld Euc() const { return x * x + y * y; }
	ld mag() const { return sqrt(Euc()); }
	Pos unit() const { return *this / mag(); }
	ld rad() const { return atan2(y, x); }
	friend ld rad(const Pos& p1, const Pos& p2) { return atan2l(p1 / p2, p1 * p2); }
	int quad() const { return sign(y) == 1 || (sign(y) == 0 && sign(x) >= 0); }
	friend bool cmpq(const Pos& a, const Pos& b) { return (a.quad() != b.quad()) ? a.quad() < b.quad() : a / b > 0; }
	bool close(const Pos& p) const { return zero((*this - p).Euc()); }
	friend std::istream& operator >> (std::istream& is, Pos& p) { is >> p.x >> p.y; return is; }
	friend std::ostream& operator << (std::ostream& os, const Pos& p) { os << "(" << p.x << ", " << p.y << ")"; return os; }
}; const Pos O = Pos(0, 0);
typedef std::vector<Pos> Polygon;
struct Vec {
	ld vy, vx;
	Vec(ld Y = 0, ld X = 0) : vy(Y), vx(X) {}
	bool operator == (const Vec& v) const { return (zero(vy - v.vy) && zero(vx - v.vx)); }
	bool operator < (const Vec& v) const { return zero(vy - v.vy) ? vx < v.vx : vy < v.vy; }
	ld operator * (const Vec& v) const { return vy * v.vy + vx * v.vx; }
	ld operator / (const Vec& v) const { return vy * v.vx - vx * v.vy; }
	Vec operator ~ () const { return { -vx, vy }; }
	Vec& operator *= (const ld& scalar) { vy *= scalar; vx *= scalar; return *this; }
	Vec& operator /= (const ld& scalar) { vy /= scalar; vx /= scalar; return *this; }
}; const Vec Zero = { 0, 0 };
struct Line {//ax + by = c
	Vec s;
	ld c;
	Line(Vec V = Vec(0, 0), ld C = 0) : s(V), c(C) {}
	Line(Vec V = Vec(0, 0), Pos p = Pos(0, 0)) : s(V) { c = s.vy * p.x + s.vx * p.y; }
	Line(Pos ps = Pos(0, 0), Pos pe = Pos(0, 0)) {
		ld dy, dx;
		dy = pe.y - ps.y;
		dx = ps.x - pe.x;
		s = Vec(dy, dx);
		c = dy * ps.x + dx * ps.y;
	}
	bool operator < (const Line& l) const {
		bool f1 = Zero < s;
		bool f2 = Zero < l.s;
		if (f1 != f2) return f1;
		ld CCW = s / l.s;
		return zero(CCW) ? c * hypot(l.s.vy, l.s.vx) < l.c * hypot(s.vy, s.vx) : CCW > 0;
	}
	ld operator / (const Line& l) const { return s / l.s; }
	ld operator * (const Line& l) const { return s * l.s; }
	Line operator + (const ld& scalar) const { return Line(s, c + hypot(s.vy, s.vx) * scalar); }
	Line operator - (const ld& scalar) const { return Line(s, c - hypot(s.vy, s.vx) * scalar); }
	Line operator * (const ld& scalar) const { return Line({ s.vy * scalar, s.vx * scalar }, c * scalar); }
	Line& operator += (const ld& scalar) { c += hypot(s.vy, s.vx) * scalar; return *this; }
	Line& operator -= (const ld& scalar) { c -= hypot(s.vy, s.vx) * scalar; return *this; }
	Line& operator *= (const ld& scalar) { s *= scalar, c *= scalar; return *this; }
	ld dist(const Pos& p) const { return s.vy * p.x + s.vx * p.y; }
	ld above(const Pos& p) const { return s.vy * p.x + s.vx * p.y - c; }
	friend std::ostream& operator << (std::ostream& os, const Line& l) { os << l.s.vy << " " << l.s.vx << " " << l.c; return os; }
};
const Line Xaxis = { { 0, -1 }, 0 };
const Line Yaxis = { { 1, 0 }, 0 };
Line L(const Pos& s, const Pos& e) { return Line(s, e); }
Line rotate90(const Line& l, const Pos& p) { return Line(~l.s, p); }
Pos intersection(const Line& l1, const Line& l2) {
	Vec v1 = l1.s, v2 = l2.s;
	ld det = v1 / v2;
	return {
		(l1.c * v2.vx - l2.c * v1.vx) / det,
		(l2.c * v1.vy - l1.c * v2.vy) / det,
	};
}
ld cross(const Pos& d1, const Pos& d2, const Pos& d3) { return (d2 - d1) / (d3 - d2); }
ld cross(const Pos& d1, const Pos& d2, const Pos& d3, const Pos& d4) { return (d2 - d1) / (d4 - d3); }
int ccw(const Pos& d1, const Pos& d2, const Pos& d3) { return sign(cross(d1, d2, d3)); }
ld dot(const Pos& d1, const Pos& d2, const Pos& d3) { return (d2 - d1) * (d3 - d2); }
ld dot(const Pos& d1, const Pos& d2, const Pos& d3, const Pos& d4) { return (d2 - d1) * (d4 - d3); }
bool on_seg_strong(const Pos& d1, const Pos& d2, const Pos& d3) { return !ccw(d1, d2, d3) && sign(dot(d1, d3, d2)) >= 0; }
bool on_seg_weak(const Pos& d1, const Pos& d2, const Pos& d3) { return !ccw(d1, d2, d3) && sign(dot(d1, d3, d2)) > 0; }
Pos intersection(const Pos& p1, const Pos& p2, const Pos& q1, const Pos& q2) { ld a1 = cross(q1, q2, p1), a2 = -cross(q1, q2, p2); return (p1 * a2 + p2 * a1) / (a1 + a2); }
ld area(const Polygon& H) {
	ld ret = 0;
	int sz = H.size();
	for (int i = 0; i < sz; i++) ret += H[i] / H[(i + 1) % sz];
	return ret;
}
bool norm(Polygon& H) {
	ld a = area(H);
	if (zero(a)) return 1;
	if (a < 0) std::reverse(H.begin(), H.end());
	return 0;
}
Polygon rotate_and_norm(Polygon B, const int& j0, const Polygon& A, const int& i0, const ld& t) {
	int sz = B.size();
	for (int j = 0; j < sz; j++) B[j] = B[j].rot(t);
	Pos v = A[i0] - B[j0];
	for (int j = 0; j < sz; j++) B[j] += v;
	return B;
}
struct Circle {
	Pos c;
	ld r;
	Circle(Pos C = Pos(0, 0), ld R = 0) : c(C), r(R) {}
	bool operator == (const Circle& C) const { return c == C.c && std::abs(r - C.r) < TOL; }
	bool operator != (const Circle& C) const { return !(*this == C); }
	bool operator > (const Pos& p) const { return r > (c - p).mag(); }
	bool operator >= (const Pos& p) const { return r + TOL > (c - p).mag(); }
	bool operator < (const Pos& p) const { return r < (c - p).mag(); }
	Circle operator + (const Circle& C) const { return { {c.x + C.c.x, c.y + C.c.y}, r + C.r }; }
	Circle operator - (const Circle& C) const { return { {c.x - C.c.x, c.y - C.c.y}, r - C.r }; }
	ld H(const ld& th) const { return sin(th) * c.x + cos(th) * c.y + r; }// coord trans | check right
	ld A() const { return r * r * PI; }
	friend std::istream& operator >> (std::istream& is, Circle& c) { is >> c.c.x >> c.c.y >> c.r; return is; }
	friend std::ostream& operator << (std::ostream& os, const Circle& c) { os << c.c.x << " " << c.c.y << " " << c.r; return os; }
} INVAL = { { 0, 0 }, -1 };
Circle enclose_circle(const Pos& u, const Pos& v) {
	Pos c = (u + v) * .5;
	return Circle(c, (c - u).mag());
}
Circle enclose_circle(const Pos& u, const Pos& v, const Pos& w) {
	//Pos v1 = v - u, v2 = w - v;
	//if (zero(v1 / v2)) return INVAL;
	//Pos m1 = (u + v) * .5, m2 = (v + w) * .5;
	//Pos p1 = m1 + ~v1, p2 = m2 + ~v2;
	//Pos c = intersection(m1, p1, m2, p2);
	//return Circle(c, (c - u).mag());
	Line l1 = rotate90(L(u, v), (u + v) * .5);
	Line l2 = rotate90(L(v, w), (v + w) * .5);
	if (zero(l1 / l2)) return { { 0, 0 }, -1 };
	Pos c = intersection(l1, l2);
	ld r = (c - u).mag();
	return Circle(c, r);
}
Circle minimum_enclose_circle(std::vector<Pos> P) {
	shuffle(P.begin(), P.end(), std::mt19937(0x14004));
	Circle mec = INVAL;
	int sz = P.size();
	for (int i = 0; i < sz; i++) {
		if (mec.r < -1 || mec < P[i]) {
			mec = Circle(P[i], 0);
			for (int j = 0; j <= i; j++) {
				if (mec < P[j]) {
					Circle ans = enclose_circle(P[i], P[j]);
					if (zero(mec.r)) { mec = ans; continue; }
					Circle l = INVAL, r = INVAL;
					for (int k = 0; k <= j; k++) {
						if (ans < P[k]) {
							int CCW = ccw(P[i], P[j], P[k]);
							Circle c = enclose_circle(P[i], P[j], P[k]);
							if (c.r < 0) continue;
							else if (CCW > 0 && (l.r < 0 || cross(P[i], P[j], c.c) > cross(P[i], P[j], l.c))) l = c;
							else if (CCW < 0 && (r.r < 0 || cross(P[i], P[j], c.c) < cross(P[i], P[j], r.c))) r = c;
						}
					}
					if (l.r < 0 && r.r < 0) mec = ans;
					else if (l.r < 0) mec = r;
					else if (r.r < 0) mec = l;
					else mec = l.r < r.r ? l : r;
				}
			}
		}
	}
	return mec;
}
Circle minimum_enclose_circle(Polygon A, int i, Polygon B, int j, ld d) {
	Polygon V;
	Pos v = (A[(i + 1) % A.size()] - B[(j + 1) % B.size()]).unit() * d;
	for (Pos& p : B) p += v;
	for (const Pos& p : A) V.push_back(p);
	for (const Pos& p : B) V.push_back(p);
	return minimum_enclose_circle(V);
}
ld ternary_search(const Polygon& A, const int& i, const Polygon& B, const int& j) {
	int a = A.size(), b = B.size();
	const Pos& pa = A[(i + 1) % a], & pb = B[(j + 1) % b];
	ld s = 0, e = (pa - pb).mag(), m1, m2, r1 = 0, r2 = 0;
	int cnt = 50; while (cnt--) {
		m1 = (s + s + e) / 3;
		m2 = (s + e + e) / 3;
		r1 = minimum_enclose_circle(A, i, B, j, m1).r;
		r2 = minimum_enclose_circle(A, i, B, j, m2).r;
		if (r1 > r2) s = m1;
		else e = m2;
	}
	return r2;
}
ld fit(const Polygon& P, const ld& r) {
	auto dist = [&](const Pos& s1, const Pos& s2, const Pos& c) -> ld {
		ld d = cross(s1, s2, c) / (s1 - s2).mag();
		return r + d;
		};
	int sz = P.size();
	ld ret = INF;
	for (int i = 0; i < sz; i++) {
		for (int j = i + 1; j < sz; j++) {
			ld tmp = INF;
			const Pos& p = P[i], & q = P[j];
			Pos mid = (p + q) * .5;
			Pos vec = p - mid;
			ld h = vec.mag();
			if (sign(h - r) > 0) continue;
			ld w = sqrt(r * r - h * h);
			Pos c1 = mid + ~vec.unit() * w;
			Pos c2 = mid - ~vec.unit() * w;
			for (const Pos& c : { c1, c2 }) {
				for (int k = 0; k < sz; k++) {
					const Pos& p0 = P[(k - 1 + sz) % sz], & p1 = P[k], & p2 = P[(k + 1) % sz];
					assert(ccw(p0, p1, p2) >= 0);
					if (k == i || k == j) continue;
					if (sign((P[k] - c).mag() - r) > 0) { tmp = INF; break; }
					if (ccw(p0, p1, c) < 0 && ccw(p1, p2, c) < 0 && dot(p0, p1, c) > 0 && dot(p2, p1, c) > 0) {
						tmp = std::min(tmp, r - (c - p1).mag());
					}
					else tmp = std::min({ tmp, dist(p0, p1, c), dist(p1, p2, c) });
				}
				ret = std::min(ret, tmp);
			}
		}
	}
	return ret;
}
bool fit(const Polygon& A, const Polygon& B, const ld& r) {
	ld da = fit(A, r), db = fit(B, r);
	return sign(r + r - (da + db)) >= 0 ? 1 : 0;
}
ld bi_search(const Polygon& A, const Polygon& B, ld s, ld e) {
	int cnt = 30; while (cnt--) {
		ld m = (s + e) * .5;
		if (fit(A, B, m)) e = m;
		else s = m;
	}
	return (s + e) * .5;
}
bool query() {
	std::cin >> N;
	if (!N) return 0;
	Polygon A(N);
	for (Pos& p : A) std::cin >> p;
	norm(A);
	std::cin >> M;
	Polygon B(M);
	for (Pos& p : B) std::cin >> p;
	norm(B);
	ld ret = INF;
	ld r1 = INF;
	ld ra = minimum_enclose_circle(A).r, rb = minimum_enclose_circle(B).r;
	for (int i = 0; i < N; i++) {
		Pos& I0 = A[i], & I1 = A[(i + 1) % N];
		for (int j = 0; j < M; j++) {
			Pos& J0 = B[j], & J1 = B[(j + 1) % M];
			ld t = rad(J0 - J1, I1 - I0);
			Polygon B2 = rotate_and_norm(B, j, A, i, t);
			r1 = std::min(r1, ternary_search(A, i, B2, j));
		}
	}
	ld r2 = bi_search(A, B, std::max(ra, rb), r1);
	ret = std::min({ ret, r1, r2 }) * 2;
	ans.push_back(ret);
	return 1;
}
void solve() {
	std::cin.tie(0)->sync_with_stdio(0);
	std::cout.tie(0);
	std::cout << std::fixed;
	std::cout.precision(15);
	while (query());
	for (const ld& ret : ans) std::cout << ret << "\n";
	return;
}
int main() { solve(); return 0; }//boj20231 Idealistic Canister
accuracy: 1
time_ms: 7350
memory_kb: 3968
final_rank: 10

code_snippet: #define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <algorithm>
#include <vector>
#include <cmath>
#include <cstring>
#include <cassert>
#include <random>
#include <array>
#include <tuple>
typedef long long ll;
//typedef long double ld;
typedef double ld;
typedef std::pair<int, int> pi;
typedef std::vector<ld> Vld;
const ld INF = 1e17;
const ld TOL = 1e-7;
const ld PI = acos(-1);
const int LEN = 1e3;
inline int sign(const ld& x) { return x < -TOL ? -1 : x > TOL; }
inline bool zero(const ld& x) { return !sign(x); }
inline bool eq(const ld& x, const ld& y) { return zero(x - y); }

Vld ans;
int N, M;
struct Pos {
	ld x, y;
	Pos(ld X = 0, ld Y = 0) : x(X), y(Y) {}
	bool operator == (const Pos& p) const { return zero(x - p.x) && zero(y - p.y); }
	bool operator != (const Pos& p) const { return !zero(x - p.x) || !zero(y - p.y); }
	bool operator < (const Pos& p) const { return zero(x - p.x) ? y < p.y : x < p.x; }
	//bool operator < (const Pos& r) const { return x == r.x ? y == r.y ? d < r.d : y < r.y : x < r.x; }
	//bool operator < (const Pos& r) const { return zero(x - r.x) ? zero(y - r.y) ? d < r.d : y < r.y : x < r.x; }
	bool operator <= (const Pos& p) const { return *this < p || *this == p; }
	Pos operator + (const Pos& p) const { return { x + p.x, y + p.y }; }
	Pos operator - (const Pos& p) const { return { x - p.x, y - p.y }; }
	Pos operator * (const ld& scalar) const { return { x * scalar, y * scalar }; }
	Pos operator / (const ld& scalar) const { return { x / scalar, y / scalar }; }
	ld operator * (const Pos& p) const { return x * p.x + y * p.y; }
	ld operator / (const Pos& p) const { return x * p.y - y * p.x; }
	Pos operator ^ (const Pos& p) const { return { x * p.x, y * p.y }; }
	Pos& operator += (const Pos& p) { x += p.x; y += p.y; return *this; }
	Pos& operator -= (const Pos& p) { x -= p.x; y -= p.y; return *this; }
	Pos& operator *= (const ld& scale) { x *= scale; y *= scale; return *this; }
	Pos& operator /= (const ld& scale) { x /= scale; y /= scale; return *this; }
	Pos operator - () const { return { -x, -y }; }
	Pos operator ~ () const { return { -y, x }; }
	Pos operator ! () const { return { y, x }; }
	ld xy() const { return x * y; }
	Pos rot(ld the) const { return { x * cos(the) - y * sin(the), x * sin(the) + y * cos(the) }; }
	ld Euc() const { return x * x + y * y; }
	ld mag() const { return sqrt(Euc()); }
	Pos unit() const { return *this / mag(); }
	ld rad() const { return atan2(y, x); }
	friend ld rad(const Pos& p1, const Pos& p2) { return atan2l(p1 / p2, p1 * p2); }
	int quad() const { return sign(y) == 1 || (sign(y) == 0 && sign(x) >= 0); }
	friend bool cmpq(const Pos& a, const Pos& b) { return (a.quad() != b.quad()) ? a.quad() < b.quad() : a / b > 0; }
	bool close(const Pos& p) const { return zero((*this - p).Euc()); }
	friend std::istream& operator >> (std::istream& is, Pos& p) { is >> p.x >> p.y; return is; }
	friend std::ostream& operator << (std::ostream& os, const Pos& p) { os << "(" << p.x << ", " << p.y << ")"; return os; }
}; const Pos O = Pos(0, 0);
typedef std::vector<Pos> Polygon;
struct Vec {
	ld vy, vx;
	Vec(ld Y = 0, ld X = 0) : vy(Y), vx(X) {}
	bool operator == (const Vec& v) const { return (zero(vy - v.vy) && zero(vx - v.vx)); }
	bool operator < (const Vec& v) const { return zero(vy - v.vy) ? vx < v.vx : vy < v.vy; }
	ld operator * (const Vec& v) const { return vy * v.vy + vx * v.vx; }
	ld operator / (const Vec& v) const { return vy * v.vx - vx * v.vy; }
	Vec operator ~ () const { return { -vx, vy }; }
	Vec& operator *= (const ld& scalar) { vy *= scalar; vx *= scalar; return *this; }
	Vec& operator /= (const ld& scalar) { vy /= scalar; vx /= scalar; return *this; }
}; const Vec Zero = { 0, 0 };
struct Line {//ax + by = c
	Vec s;
	ld c;
	Line(Vec V = Vec(0, 0), ld C = 0) : s(V), c(C) {}
	Line(Vec V = Vec(0, 0), Pos p = Pos(0, 0)) : s(V) { c = s.vy * p.x + s.vx * p.y; }
	Line(Pos ps = Pos(0, 0), Pos pe = Pos(0, 0)) {
		ld dy, dx;
		dy = pe.y - ps.y;
		dx = ps.x - pe.x;
		s = Vec(dy, dx);
		c = dy * ps.x + dx * ps.y;
	}
	bool operator < (const Line& l) const {
		bool f1 = Zero < s;
		bool f2 = Zero < l.s;
		if (f1 != f2) return f1;
		ld CCW = s / l.s;
		return zero(CCW) ? c * hypot(l.s.vy, l.s.vx) < l.c * hypot(s.vy, s.vx) : CCW > 0;
	}
	ld operator / (const Line& l) const { return s / l.s; }
	ld operator * (const Line& l) const { return s * l.s; }
	Line operator + (const ld& scalar) const { return Line(s, c + hypot(s.vy, s.vx) * scalar); }
	Line operator - (const ld& scalar) const { return Line(s, c - hypot(s.vy, s.vx) * scalar); }
	Line operator * (const ld& scalar) const { return Line({ s.vy * scalar, s.vx * scalar }, c * scalar); }
	Line& operator += (const ld& scalar) { c += hypot(s.vy, s.vx) * scalar; return *this; }
	Line& operator -= (const ld& scalar) { c -= hypot(s.vy, s.vx) * scalar; return *this; }
	Line& operator *= (const ld& scalar) { s *= scalar, c *= scalar; return *this; }
	ld dist(const Pos& p) const { return s.vy * p.x + s.vx * p.y; }
	ld above(const Pos& p) const { return s.vy * p.x + s.vx * p.y - c; }
	friend std::ostream& operator << (std::ostream& os, const Line& l) { os << l.s.vy << " " << l.s.vx << " " << l.c; return os; }
};
const Line Xaxis = { { 0, -1 }, 0 };
const Line Yaxis = { { 1, 0 }, 0 };
Line L(const Pos& s, const Pos& e) { return Line(s, e); }
Line rotate90(const Line& l, const Pos& p) { return Line(~l.s, p); }
Pos intersection(const Line& l1, const Line& l2) {
	Vec v1 = l1.s, v2 = l2.s;
	ld det = v1 / v2;
	return {
		(l1.c * v2.vx - l2.c * v1.vx) / det,
		(l2.c * v1.vy - l1.c * v2.vy) / det,
	};
}
ld cross(const Pos& d1, const Pos& d2, const Pos& d3) { return (d2 - d1) / (d3 - d2); }
ld cross(const Pos& d1, const Pos& d2, const Pos& d3, const Pos& d4) { return (d2 - d1) / (d4 - d3); }
int ccw(const Pos& d1, const Pos& d2, const Pos& d3) { return sign(cross(d1, d2, d3)); }
ld dot(const Pos& d1, const Pos& d2, const Pos& d3) { return (d2 - d1) * (d3 - d2); }
ld dot(const Pos& d1, const Pos& d2, const Pos& d3, const Pos& d4) { return (d2 - d1) * (d4 - d3); }
bool on_seg_strong(const Pos& d1, const Pos& d2, const Pos& d3) { return !ccw(d1, d2, d3) && sign(dot(d1, d3, d2)) >= 0; }
bool on_seg_weak(const Pos& d1, const Pos& d2, const Pos& d3) { return !ccw(d1, d2, d3) && sign(dot(d1, d3, d2)) > 0; }
Pos intersection(const Pos& p1, const Pos& p2, const Pos& q1, const Pos& q2) { ld a1 = cross(q1, q2, p1), a2 = -cross(q1, q2, p2); return (p1 * a2 + p2 * a1) / (a1 + a2); }
ld area(const Polygon& H) {
	ld ret = 0;
	int sz = H.size();
	for (int i = 0; i < sz; i++) ret += H[i] / H[(i + 1) % sz];
	return ret;
}
bool norm(Polygon& H) {
	ld a = area(H);
	if (zero(a)) return 1;
	if (a < 0) std::reverse(H.begin(), H.end());
	return 0;
}
Polygon rotate_and_norm(Polygon B, const int& j0, const Polygon& A, const int& i0, const ld& t) {
	int sz = B.size();
	for (int j = 0; j < sz; j++) B[j] = B[j].rot(t);
	Pos v = A[i0] - B[j0];
	for (int j = 0; j < sz; j++) B[j] += v;
	return B;
}
struct Circle {
	Pos c;
	ld r;
	Circle(Pos C = Pos(0, 0), ld R = 0) : c(C), r(R) {}
	bool operator == (const Circle& C) const { return c == C.c && std::abs(r - C.r) < TOL; }
	bool operator != (const Circle& C) const { return !(*this == C); }
	bool operator > (const Pos& p) const { return r > (c - p).mag(); }
	bool operator >= (const Pos& p) const { return r + TOL > (c - p).mag(); }
	bool operator < (const Pos& p) const { return r < (c - p).mag(); }
	Circle operator + (const Circle& C) const { return { {c.x + C.c.x, c.y + C.c.y}, r + C.r }; }
	Circle operator - (const Circle& C) const { return { {c.x - C.c.x, c.y - C.c.y}, r - C.r }; }
	ld H(const ld& th) const { return sin(th) * c.x + cos(th) * c.y + r; }// coord trans | check right
	ld A() const { return r * r * PI; }
	friend std::istream& operator >> (std::istream& is, Circle& c) { is >> c.c.x >> c.c.y >> c.r; return is; }
	friend std::ostream& operator << (std::ostream& os, const Circle& c) { os << c.c.x << " " << c.c.y << " " << c.r; return os; }
} INVAL = { { 0, 0 }, -1 };
Circle enclose_circle(const Pos& u, const Pos& v) {
	Pos c = (u + v) * .5;
	return Circle(c, (c - u).mag());
}
Circle enclose_circle(const Pos& u, const Pos& v, const Pos& w) {
	Line l1 = rotate90(L(u, v), (u + v) * .5);
	Line l2 = rotate90(L(v, w), (v + w) * .5);
	if (zero(l1 / l2)) return { { 0, 0 }, -1 };
	Pos c = intersection(l1, l2);
	ld r = (c - u).mag();
	return Circle(c, r);
}
Circle minimum_enclose_circle(std::vector<Pos> P) {
	shuffle(P.begin(), P.end(), std::mt19937(0x14004));
	Circle mec = INVAL;
	int sz = P.size();
	for (int i = 0; i < sz; i++) {
		if (mec.r < -1 || mec < P[i]) {
			mec = Circle(P[i], 0);
			for (int j = 0; j <= i; j++) {
				if (mec < P[j]) {
					Circle ans = enclose_circle(P[i], P[j]);
					if (zero(mec.r)) { mec = ans; continue; }
					Circle l = INVAL, r = INVAL;
					for (int k = 0; k <= j; k++) {
						if (ans < P[k]) {
							int CCW = ccw(P[i], P[j], P[k]);
							Circle c = enclose_circle(P[i], P[j], P[k]);
							if (c.r < 0) continue;
							else if (CCW > 0 && (l.r < 0 || cross(P[i], P[j], c.c) > cross(P[i], P[j], l.c))) l = c;
							else if (CCW < 0 && (r.r < 0 || cross(P[i], P[j], c.c) < cross(P[i], P[j], r.c))) r = c;
						}
					}
					if (l.r < 0 && r.r < 0) mec = ans;
					else if (l.r < 0) mec = r;
					else if (r.r < 0) mec = l;
					else mec = l.r < r.r ? l : r;
				}
			}
		}
	}
	return mec;
}
Circle minimum_enclose_circle(Polygon A, int i, Polygon B, int j, ld d) {
	Polygon V;
	Pos v = (A[(i + 1) % A.size()] - B[(j + 1) % B.size()]).unit() * d;
	for (Pos& p : B) p += v;
	for (const Pos& p : A) V.push_back(p);
	for (const Pos& p : B) V.push_back(p);
	return minimum_enclose_circle(V);
}
ld ternary_search(const Polygon& A, const int& i, const Polygon& B, const int& j) {
	int a = A.size(), b = B.size();
	const Pos& pa = A[(i + 1) % a], & pb = B[(j + 1) % b];
	ld s = 0, e = (pa - pb).mag(), m1, m2, r1 = 0, r2 = 0;
	int cnt = 50; while (cnt--) {
		m1 = (s + s + e) / 3;
		m2 = (s + e + e) / 3;
		r1 = minimum_enclose_circle(A, i, B, j, m1).r;
		r2 = minimum_enclose_circle(A, i, B, j, m2).r;
		if (r1 > r2) s = m1;
		else e = m2;
	}
	return r2;
}
ld ternary_search(const Pos& p0, const Pos& p1, const Pos& p2, const Pos& c, const ld& r) {
	Pos vec, v1, v2;
	auto dist = [&](const ld& t) -> ld {
		Pos s2 = p1 + vec.rot(t);
		ld d = cross(p1, s2, c) / (p1 - s2).mag();
		return r - d;
		};
	vec = (p0 - p1);
	v1 = ~(p0 - p1), v2 = ~(p2 - p1);
	ld s = 0, e = rad(v1, v2), m1, m2, d1, d2;
	int cnt = 25; while (cnt--) {
		m1 = (s + s + e) / 3;
		m2 = (s + e + e) / 3;
		d1 = dist(m1);
		d2 = dist(m2);
		if (sign(d1 < d2)) s = m1;
		else e = m2;
	}
	return (s + e) * .5;
}
ld fit(const Polygon& P, const ld& r) {
	auto dist = [&](const Pos& s1, const Pos& s2, const Pos& c) -> ld {
		ld d = cross(s1, s2, c) / (s1 - s2).mag();
		return r + d;
		};
	int sz = P.size();
	ld ret = INF;
	for (int i = 0; i < sz; i++) {
		for (int j = i + 1; j < sz; j++) {
			ld tmp = INF;
			const Pos& p = P[i], & q = P[j];
			Pos mid = (p + q) * .5;
			Pos vec = p - mid;
			ld h = vec.mag();
			if (sign(h - r) > 0) continue;
			ld w = sqrt(r * r - h * h);
			Pos c1 = mid + ~vec.unit() * w;
			Pos c2 = mid - ~vec.unit() * w;
			for (const Pos& c : { c1, c2 }) {
				for (int k = 0; k < sz; k++) {
					const Pos& p0 = P[(k - 1 + sz) % sz], & p1 = P[k], & p2 = P[(k + 1) % sz];
					assert(ccw(p0, p1, p2) >= 0);
					if (k == i || k == j) continue;
					if (sign((P[k] - c).mag() - r) > 0) { tmp = INF; break; }
					if (ccw(p0, p1, c) < 0 && ccw(p1, p2, c) < 0 && dot(p0, p1, c) > 0 && dot(p2, p1, c) > 0) {
						tmp = std::min(tmp, r - (c - p1).mag());
					}
					else tmp = std::min({ tmp, dist(p0, p1, c), dist(p1, p2, c) });
				}
				ret = std::min(ret, tmp);
			}
		}
	}
	return ret;
}
bool fit(const Polygon& A, const Polygon& B, const ld& r) {
	ld da = fit(A, r), db = fit(B, r);
	return sign(r + r - (da + db)) >= 0 ? 1 : 0;
}
ld bi_search(const Polygon& A, const Polygon& B, ld s, ld e) {
	int cnt = 30; while (cnt--) {
		ld m = (s + e) * .5;
		if (fit(A, B, m)) e = m;
		else s = m;
	}
	return (s + e) * .5;
}
bool query() {
	std::cin >> N;
	if (!N) return 0;
	Polygon A(N);
	for (Pos& p : A) std::cin >> p;
	norm(A);
	std::cin >> M;
	Polygon B(M);
	for (Pos& p : B) std::cin >> p;
	norm(B);
	ld ret = INF;
	ld r1 = INF;
	ld ra = minimum_enclose_circle(A).r, rb = minimum_enclose_circle(B).r;
	for (int i = 0; i < N; i++) {
		Pos& I0 = A[i], & I1 = A[(i + 1) % N];
		for (int j = 0; j < M; j++) {
			Pos& J0 = B[j], & J1 = B[(j + 1) % M];
			ld t = rad(J0 - J1, I1 - I0);
			Polygon B2 = rotate_and_norm(B, j, A, i, t);
			r1 = std::min(r1, ternary_search(A, i, B2, j));
		}
	}
	ld r2 = bi_search(A, B, std::max(ra, rb), r1);
	ret = std::min({ ret, r1, r2 }) * 2;
	ans.push_back(ret);
	return 1;
}
void solve() {
	std::cin.tie(0)->sync_with_stdio(0);
	std::cout.tie(0);
	std::cout << std::fixed;
	std::cout.precision(15);
	while (query());
	for (const ld& ret : ans) std::cout << ret << "\n";
	return;
}
int main() { solve(); return 0; }//boj20231 Idealistic Canister
accuracy: 1
time_ms: 7310
memory_kb: 3952
final_rank: 9

code_snippet: #define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <algorithm>
#include <vector>
#include <cmath>
#include <cstring>
#include <cassert>
#include <random>
#include <array>
#include <tuple>
typedef long long ll;
//typedef long double ld;
typedef double ld;
typedef std::pair<int, int> pi;
typedef std::vector<ld> Vld;
const ld INF = 1e17;
const ld TOL = 1e-7;
const ld PI = acos(-1);
const int LEN = 1e3;
inline int sign(const ld& x) { return x < -TOL ? -1 : x > TOL; }
inline bool zero(const ld& x) { return !sign(x); }
inline bool eq(const ld& x, const ld& y) { return zero(x - y); }

Vld ans;
int N, M;
struct Pos {
	ld x, y;
	Pos(ld X = 0, ld Y = 0) : x(X), y(Y) {}
	bool operator == (const Pos& p) const { return zero(x - p.x) && zero(y - p.y); }
	bool operator != (const Pos& p) const { return !zero(x - p.x) || !zero(y - p.y); }
	bool operator < (const Pos& p) const { return zero(x - p.x) ? y < p.y : x < p.x; }
	//bool operator < (const Pos& r) const { return x == r.x ? y == r.y ? d < r.d : y < r.y : x < r.x; }
	//bool operator < (const Pos& r) const { return zero(x - r.x) ? zero(y - r.y) ? d < r.d : y < r.y : x < r.x; }
	bool operator <= (const Pos& p) const { return *this < p || *this == p; }
	Pos operator + (const Pos& p) const { return { x + p.x, y + p.y }; }
	Pos operator - (const Pos& p) const { return { x - p.x, y - p.y }; }
	Pos operator * (const ld& scalar) const { return { x * scalar, y * scalar }; }
	Pos operator / (const ld& scalar) const { return { x / scalar, y / scalar }; }
	ld operator * (const Pos& p) const { return x * p.x + y * p.y; }
	ld operator / (const Pos& p) const { return x * p.y - y * p.x; }
	Pos operator ^ (const Pos& p) const { return { x * p.x, y * p.y }; }
	Pos& operator += (const Pos& p) { x += p.x; y += p.y; return *this; }
	Pos& operator -= (const Pos& p) { x -= p.x; y -= p.y; return *this; }
	Pos& operator *= (const ld& scale) { x *= scale; y *= scale; return *this; }
	Pos& operator /= (const ld& scale) { x /= scale; y /= scale; return *this; }
	Pos operator - () const { return { -x, -y }; }
	Pos operator ~ () const { return { -y, x }; }
	Pos operator ! () const { return { y, x }; }
	ld xy() const { return x * y; }
	Pos rot(ld the) const { return { x * cos(the) - y * sin(the), x * sin(the) + y * cos(the) }; }
	ld Euc() const { return x * x + y * y; }
	ld mag() const { return sqrt(Euc()); }
	Pos unit() const { return *this / mag(); }
	ld rad() const { return atan2(y, x); }
	friend ld rad(const Pos& p1, const Pos& p2) { return atan2l(p1 / p2, p1 * p2); }
	int quad() const { return sign(y) == 1 || (sign(y) == 0 && sign(x) >= 0); }
	friend bool cmpq(const Pos& a, const Pos& b) { return (a.quad() != b.quad()) ? a.quad() < b.quad() : a / b > 0; }
	bool close(const Pos& p) const { return zero((*this - p).Euc()); }
	friend std::istream& operator >> (std::istream& is, Pos& p) { is >> p.x >> p.y; return is; }
	friend std::ostream& operator << (std::ostream& os, const Pos& p) { os << "(" << p.x << ", " << p.y << ")"; return os; }
}; const Pos O = Pos(0, 0);
typedef std::vector<Pos> Polygon;
struct Vec {
	ld vy, vx;
	Vec(ld Y = 0, ld X = 0) : vy(Y), vx(X) {}
	bool operator == (const Vec& v) const { return (zero(vy - v.vy) && zero(vx - v.vx)); }
	bool operator < (const Vec& v) const { return zero(vy - v.vy) ? vx < v.vx : vy < v.vy; }
	ld operator * (const Vec& v) const { return vy * v.vy + vx * v.vx; }
	ld operator / (const Vec& v) const { return vy * v.vx - vx * v.vy; }
	Vec operator ~ () const { return { -vx, vy }; }
	Vec& operator *= (const ld& scalar) { vy *= scalar; vx *= scalar; return *this; }
	Vec& operator /= (const ld& scalar) { vy /= scalar; vx /= scalar; return *this; }
}; const Vec Zero = { 0, 0 };
struct Line {//ax + by = c
	Vec s;
	ld c;
	Line(Vec V = Vec(0, 0), ld C = 0) : s(V), c(C) {}
	Line(Vec V = Vec(0, 0), Pos p = Pos(0, 0)) : s(V) { c = s.vy * p.x + s.vx * p.y; }
	Line(Pos ps = Pos(0, 0), Pos pe = Pos(0, 0)) {
		ld dy, dx;
		dy = pe.y - ps.y;
		dx = ps.x - pe.x;
		s = Vec(dy, dx);
		c = dy * ps.x + dx * ps.y;
	}
	bool operator < (const Line& l) const {
		bool f1 = Zero < s;
		bool f2 = Zero < l.s;
		if (f1 != f2) return f1;
		ld CCW = s / l.s;
		return zero(CCW) ? c * hypot(l.s.vy, l.s.vx) < l.c * hypot(s.vy, s.vx) : CCW > 0;
	}
	ld operator / (const Line& l) const { return s / l.s; }
	ld operator * (const Line& l) const { return s * l.s; }
	Line operator + (const ld& scalar) const { return Line(s, c + hypot(s.vy, s.vx) * scalar); }
	Line operator - (const ld& scalar) const { return Line(s, c - hypot(s.vy, s.vx) * scalar); }
	Line operator * (const ld& scalar) const { return Line({ s.vy * scalar, s.vx * scalar }, c * scalar); }
	Line& operator += (const ld& scalar) { c += hypot(s.vy, s.vx) * scalar; return *this; }
	Line& operator -= (const ld& scalar) { c -= hypot(s.vy, s.vx) * scalar; return *this; }
	Line& operator *= (const ld& scalar) { s *= scalar, c *= scalar; return *this; }
	ld dist(const Pos& p) const { return s.vy * p.x + s.vx * p.y; }
	ld above(const Pos& p) const { return s.vy * p.x + s.vx * p.y - c; }
	friend std::ostream& operator << (std::ostream& os, const Line& l) { os << l.s.vy << " " << l.s.vx << " " << l.c; return os; }
};
const Line Xaxis = { { 0, -1 }, 0 };
const Line Yaxis = { { 1, 0 }, 0 };
Line L(const Pos& s, const Pos& e) { return Line(s, e); }
Line rotate90(const Line& l, const Pos& p) { return Line(~l.s, p); }
Pos intersection(const Line& l1, const Line& l2) {
	Vec v1 = l1.s, v2 = l2.s;
	ld det = v1 / v2;
	return {
		(l1.c * v2.vx - l2.c * v1.vx) / det,
		(l2.c * v1.vy - l1.c * v2.vy) / det,
	};
}
ld cross(const Pos& d1, const Pos& d2, const Pos& d3) { return (d2 - d1) / (d3 - d2); }
ld cross(const Pos& d1, const Pos& d2, const Pos& d3, const Pos& d4) { return (d2 - d1) / (d4 - d3); }
int ccw(const Pos& d1, const Pos& d2, const Pos& d3) { return sign(cross(d1, d2, d3)); }
ld dot(const Pos& d1, const Pos& d2, const Pos& d3) { return (d2 - d1) * (d3 - d2); }
ld dot(const Pos& d1, const Pos& d2, const Pos& d3, const Pos& d4) { return (d2 - d1) * (d4 - d3); }
bool on_seg_strong(const Pos& d1, const Pos& d2, const Pos& d3) { return !ccw(d1, d2, d3) && sign(dot(d1, d3, d2)) >= 0; }
bool on_seg_weak(const Pos& d1, const Pos& d2, const Pos& d3) { return !ccw(d1, d2, d3) && sign(dot(d1, d3, d2)) > 0; }
Pos intersection(const Pos& p1, const Pos& p2, const Pos& q1, const Pos& q2) { ld a1 = cross(q1, q2, p1), a2 = -cross(q1, q2, p2); return (p1 * a2 + p2 * a1) / (a1 + a2); }
ld area(const Polygon& H) {
	ld ret = 0;
	int sz = H.size();
	for (int i = 0; i < sz; i++) ret += H[i] / H[(i + 1) % sz];
	return ret;
}
bool norm(Polygon& H) {
	ld a = area(H);
	if (zero(a)) return 1;
	if (a < 0) std::reverse(H.begin(), H.end());
	return 0;
}
Polygon rotate_and_norm(Polygon B, const int& j0, const Polygon& A, const int& i0, const ld& t, Pos& v) {
	int sz = B.size();
	for (int j = 0; j < sz; j++) B[j] = B[j].rot(t);
	v = A[i0] - B[j0];
	for (int j = 0; j < sz; j++) B[j] += v;
	return B;
}
struct Circle {
	Pos c;
	ld r;
	Circle(Pos C = Pos(0, 0), ld R = 0) : c(C), r(R) {}
	bool operator == (const Circle& C) const { return c == C.c && std::abs(r - C.r) < TOL; }
	bool operator != (const Circle& C) const { return !(*this == C); }
	bool operator > (const Pos& p) const { return r > (c - p).mag(); }
	bool operator >= (const Pos& p) const { return r + TOL > (c - p).mag(); }
	bool operator < (const Pos& p) const { return r < (c - p).mag(); }
	Circle operator + (const Circle& C) const { return { {c.x + C.c.x, c.y + C.c.y}, r + C.r }; }
	Circle operator - (const Circle& C) const { return { {c.x - C.c.x, c.y - C.c.y}, r - C.r }; }
	ld H(const ld& th) const { return sin(th) * c.x + cos(th) * c.y + r; }// coord trans | check right
	ld A() const { return r * r * PI; }
	friend std::istream& operator >> (std::istream& is, Circle& c) { is >> c.c.x >> c.c.y >> c.r; return is; }
	friend std::ostream& operator << (std::ostream& os, const Circle& c) { os << c.c.x << " " << c.c.y << " " << c.r; return os; }
} INVAL = { { 0, 0 }, -1 };
Circle enclose_circle(const Pos& u, const Pos& v) {
	Pos c = (u + v) * .5;
	return Circle(c, (c - u).mag());
}
Circle enclose_circle(const Pos& u, const Pos& v, const Pos& w) {
	Line l1 = rotate90(L(u, v), (u + v) * .5);
	Line l2 = rotate90(L(v, w), (v + w) * .5);
	if (zero(l1 / l2)) return { { 0, 0 }, -1 };
	Pos c = intersection(l1, l2);
	ld r = (c - u).mag();
	return Circle(c, r);
}
Circle minimum_enclose_circle(std::vector<Pos> P) {
	shuffle(P.begin(), P.end(), std::mt19937(0x14004));
	Circle mec = INVAL;
	int sz = P.size();
	for (int i = 0; i < sz; i++) {
		if (mec.r < -1 || mec < P[i]) {
			mec = Circle(P[i], 0);
			for (int j = 0; j <= i; j++) {
				if (mec < P[j]) {
					Circle ans = enclose_circle(P[i], P[j]);
					if (zero(mec.r)) { mec = ans; continue; }
					Circle l = INVAL, r = INVAL;
					for (int k = 0; k <= j; k++) {
						if (ans < P[k]) {
							int CCW = ccw(P[i], P[j], P[k]);
							Circle c = enclose_circle(P[i], P[j], P[k]);
							if (c.r < 0) continue;
							else if (CCW > 0 && (l.r < 0 || cross(P[i], P[j], c.c) > cross(P[i], P[j], l.c))) l = c;
							else if (CCW < 0 && (r.r < 0 || cross(P[i], P[j], c.c) < cross(P[i], P[j], r.c))) r = c;
						}
					}
					if (l.r < 0 && r.r < 0) mec = ans;
					else if (l.r < 0) mec = r;
					else if (r.r < 0) mec = l;
					else mec = l.r < r.r ? l : r;
				}
			}
		}
	}
	return mec;
}
ld minimum_enclose_circle(Polygon A, int i, Polygon B, int j, ld d) {
	Polygon V;
	Pos v = (A[(i + 1) % A.size()] - B[(j + 1) % B.size()]).unit() * d;
	//std::cout << v.mag() << "\n";
	for (Pos& p : B) p += v;
	for (const Pos& p : A) V.push_back(p);
	for (const Pos& p : B) V.push_back(p);
	return minimum_enclose_circle(V).r;
}
ld ternary_search(const Polygon& A, const int& i, const Polygon& B, const int& j) {
	int a = A.size(), b = B.size();
	const Pos& pa = A[(i + 1) % a], & pb = B[(j + 1) % b];
	ld s = 0, e = (pa - pb).mag(), m1, m2, r1 = 0, r2 = 0;
	//std::cout << e << "\n";
	int cnt = 50; while (cnt--) {
		m1 = (s + s + e) / 3;
		m2 = (s + e + e) / 3;
		//std::cout << r1 << " " << r2 << "\n";
		r1 = minimum_enclose_circle(A, i, B, j, m1);
		r2 = minimum_enclose_circle(A, i, B, j, m2);
		if (r1 > r2) s = m1;
		else e = m2;
	}
	return r2;
}
ld ternary_search(const Pos& p0, const Pos& p1, const Pos& p2, const Pos& c, const ld& r) {
	Pos vec, v1, v2;
	auto dist = [&](const ld& t) -> ld {
		Pos s2 = p1 + vec.rot(t);
		ld d = cross(p1, s2, c) / (p1 - s2).mag();
		return r - d;
		};
	vec = (p0 - p1);
	v1 = ~(p0 - p1), v2 = ~(p2 - p1);
	ld s = 0, e = rad(v1, v2), m1, m2, d1, d2;
	int cnt = 25; while (cnt--) {
		m1 = (s + s + e) / 3;
		m2 = (s + e + e) / 3;
		d1 = dist(m1);
		d2 = dist(m2);
		if (sign(d1 < d2)) s = m1;
		else e = m2;
	}
	return (s + e) * .5;
}
ld fit(const Polygon& P, const ld& r) {
	auto dist = [&](const Pos& s1, const Pos& s2, const Pos& c) -> ld {
		ld d = cross(s1, s2, c) / (s1 - s2).mag();
		return r + d;
		};
	int sz = P.size();
	ld ret = INF;
	for (int i = 0; i < sz; i++) {
		for (int j = i + 1; j < sz; j++) {
			ld tmp = INF;
			const Pos& p = P[i], & q = P[j];
			Pos mid = (p + q) * .5;
			Pos vec = p - mid;
			ld h = vec.mag();
			if (sign(h - r) > 0) continue;
			ld w = sqrt(r * r - h * h);
			Pos c1 = mid + ~vec.unit() * w;
			Pos c2 = mid - ~vec.unit() * w;
			for (const Pos& c : { c1, c2 }) {
				//bool f = 1;
				//for (int k = 0; k < sz; k++) {
				//	const Pos& p0 = P[(k - 1 + sz) % sz], & p1 = P[k], & p2 = P[(k + 1) % sz];
				//	assert(ccw(p0, p1, p2) >= 0);
				//	if (sign((P[k] - c).mag() - r) > 0) { f = 0; break; }
				//}
				//if (!f) continue;
				for (int k = 0; k < sz; k++) {
					const Pos& p0 = P[(k - 1 + sz) % sz], & p1 = P[k], & p2 = P[(k + 1) % sz];
					assert(ccw(p0, p1, p2) >= 0);
					if (k == i || k == j) {
						assert(eq(r, (P[k] - c).mag()));
						continue;
					}
					if (sign((P[k] - c).mag() - r) > 0) { tmp = INF; break; }
					//if (eq(r, (p1 - c).mag())) tmp = std::max({ tmp, dist(p0, p1, c1), dist(p1, p2, c) });
					//else if (ccw(p0, p1, c) < 0 && ccw(p1, p2, c) < 0)
					//	tmp = std::max(tmp, ternary_search(p0, p1, p2, c, r));
					//else tmp = std::max({ tmp, dist(p0, p1, c), dist(p1, p2, c) });
					if (ccw(p0, p1, c) < 0 && ccw(p1, p2, c) < 0 && dot(p0, p1, c) > 0 && dot(p2, p1, c) > 0) {
						ld d = r - (c - p1).mag();
						//if (d < 10) {
						//	std::cout << "r:: " << r << "\n";
						//	std::cout << "p0 = " << p0 << " ";
						//	std::cout << "p1 = " << p1 << " ";
						//	std::cout << "p2 = " << p2 << " ";
						//	std::cout << "c = " << c << "\n";
						//	std::cout << "dist = " << (c - p1).mag() << "\n";
						//	std::cout << "d:: " << d << "\n";
						//}
						tmp = std::min(tmp, d);
					}
					else tmp = std::min({ tmp, dist(p0, p1, c), dist(p1, p2, c) });
				}
				ret = std::min(ret, tmp);
			}
		}
	}
	//std::cout << "ret:: " << ret << "\n";
	return ret;
}
bool fit(const Polygon& A, const Polygon& B, const ld& r) {
	ld da = fit(A, r);
	ld db = fit(B, r);
	ld D = r * 2;
	//std::cout << "r:: " << r << " da:: " << da << " db:: " << db << "\n";
	//std::cout << "r*2:: " << r * 2 << "da+db:: " << (da + db) << "\n";
	return sign(D - (da + db)) >= 0 ? 1 : 0;
}
ld bi_search(const Polygon& A, const Polygon& B, ld s, ld e) {
	int cnt = 30; while (cnt--) {
		ld m = (s + e) * .5;
		//std::cout << "m:: " << m << "\n";
		if (fit(A, B, m)) e = m;
		else s = m;
	}
	return (s + e) * .5;
}
bool query() {
	std::cin >> N;
	if (!N) return 0;
	Polygon A(N);
	for (Pos& p : A) std::cin >> p;
	norm(A);
	std::cin >> M;
	Polygon B(M);
	for (Pos& p : B) std::cin >> p;
	norm(B);
	ld ret = INF;
	ld r1 = INF;
	ld ra = minimum_enclose_circle(A).r, rb = minimum_enclose_circle(B).r;
	for (int i = 0; i < N; i++) {
		Pos& I0 = A[i], & I1 = A[(i + 1) % N];
		for (int j = 0; j < M; j++) {
			Pos& J0 = B[j], & J1 = B[(j + 1) % M];
			ld t = rad(J0 - J1, I1 - I0);
			Pos v;
			//std::cout << "FUCK::\n";
			Polygon B2 = rotate_and_norm(B, j, A, i, t, v);
			r1 = std::min(r1, ternary_search(A, i, B2, j));
		}
	}
	//std::cout << "ra :: " << ra << "\n";
	//std::cout << "rb :: " << rb << "\n";
	//std::cout << "r1 :: " << r1 << "\n";
	ld r2 = bi_search(A, B, std::max(ra, rb), r1);
	//std::cout << "r2 :: " << r2 << "\n";
	ret = std::min({ ret, r1, r2 }) * 2;
	//std::cout << "ret:: " << ret << "\n";
	ans.push_back(ret);
	return 1;
}
void solve() {
	std::cin.tie(0)->sync_with_stdio(0);
	std::cout.tie(0);
	std::cout << std::fixed;
	std::cout.precision(15);
	while (query());
	for (const ld& ret : ans) std::cout << ret << "\n";
	return;
}
int main() { solve(); return 0; }//boj20231

/*

40
904 -405
906 -400
395 -616
-16 -989
-10 -992
0 -992
27 -991
50 -990
103 -987
122 -985
130 -984
151 -981
163 -979
228 -966
253 -960
260 -958
312 -942
324 -938
369 -921
392 -912
408 -905
442 -888
467 -875
500 -857
524 -843
527 -841
570 -812
604 -786
618 -775
658 -742
687 -716
715 -688
731 -671
772 -623
797 -591
812 -570
843 -523
876 -463
878 -459
899 -416
40
-923 -266
-817 -489
-724 -604
-635 -711
-626 -718
-536 -780
-352 -889
-334 -897
-205 -934
102 -954
270 -920
357 -891
399 -874
494 -820
513 -809
629 -718
672 -680
756 -591
934 -213
944 -122
954 -4
955 30
939 178
918 261
894 345
865 405
776 565
709 644
478 832
382 877
305 890
202 900
-729 407
-755 393
-841 335
-932 234
-954 50
-956 18
-956 16
-946 -113
0

963.3270026199625

36
510 -524
616 -398
631 -375
675 -289
694 -250
726 -115
728 -73
732 15
732 95
704 213
690 261
653 334
592 434
497 533
452 547
289 518
66 478
-394 388
-638 339
-677 250
-713 163
-724 130
-735 48
-735 -41
-715 -164
-678 -266
-630 -386
-511 -533
-427 -599
-400 -619
-299 -672
-131 -723
-27 -738
110 -722
287 -678
426 -598
21
722 157
721 162
693 258
687 270
665 260
443 -142
381 -622
410 -618
442 -595
478 -567
485 -561
533 -513
599 -429
627 -392
663 -326
689 -271
699 -246
710 -214
722 -162
736 74
734 90
0

5
0 0
3 0
3 1
1 3
0 3
5
0 0
3 0
3 1
1 3
0 3
0

*/
accuracy: 1
time_ms: 7740
memory_kb: 3968
final_rank: 15

code_snippet: #define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <algorithm>
#include <vector>
#include <cmath>
#include <cstring>
#include <cassert>
#include <random>
#include <array>
#include <tuple>
typedef long long ll;
//typedef long double ld;
typedef double ld;
typedef std::pair<int, int> pi;
typedef std::vector<ld> Vld;
const ld INF = 1e17;
const ld TOL = 1e-7;
const ld PI = acos(-1);
const int LEN = 1e3;
inline int sign(const ld& x) { return x < -TOL ? -1 : x > TOL; }
inline bool zero(const ld& x) { return !sign(x); }
inline bool eq(const ld& x, const ld& y) { return zero(x - y); }

Vld ans;
int N, M;
struct Pos {
	ld x, y;
	int i, d;
	Pos(ld X = 0, ld Y = 0) : x(X), y(Y) { i = 0, d = 0; }
	bool operator == (const Pos& p) const { return zero(x - p.x) && zero(y - p.y); }
	bool operator != (const Pos& p) const { return !zero(x - p.x) || !zero(y - p.y); }
	//bool operator < (const Pos& p) const { return zero(x - p.x) ? y < p.y : x < p.x; }
	//bool operator < (const Pos& r) const { return x == r.x ? y == r.y ? d < r.d : y < r.y : x < r.x; }
	bool operator < (const Pos& r) const { return zero(x - r.x) ? zero(y - r.y) ? d < r.d : y < r.y : x < r.x; }
	bool operator <= (const Pos& p) const { return *this < p || *this == p; }
	Pos operator + (const Pos& p) const { return { x + p.x, y + p.y }; }
	Pos operator - (const Pos& p) const { return { x - p.x, y - p.y }; }
	Pos operator * (const ld& scalar) const { return { x * scalar, y * scalar }; }
	Pos operator / (const ld& scalar) const { return { x / scalar, y / scalar }; }
	ld operator * (const Pos& p) const { return x * p.x + y * p.y; }
	ld operator / (const Pos& p) const { return x * p.y - y * p.x; }
	Pos operator ^ (const Pos& p) const { return { x * p.x, y * p.y }; }
	Pos& operator += (const Pos& p) { x += p.x; y += p.y; return *this; }
	Pos& operator -= (const Pos& p) { x -= p.x; y -= p.y; return *this; }
	Pos& operator *= (const ld& scale) { x *= scale; y *= scale; return *this; }
	Pos& operator /= (const ld& scale) { x /= scale; y /= scale; return *this; }
	Pos operator - () const { return { -x, -y }; }
	Pos operator ~ () const { return { -y, x }; }
	Pos operator ! () const { return { y, x }; }
	ld xy() const { return x * y; }
	Pos rot(ld the) const { return { x * cos(the) - y * sin(the), x * sin(the) + y * cos(the) }; }
	ld Euc() const { return x * x + y * y; }
	ld mag() const { return sqrt(Euc()); }
	Pos unit() const { return *this / mag(); }
	ld rad() const { return atan2(y, x); }
	friend ld rad(const Pos& p1, const Pos& p2) { return atan2l(p1 / p2, p1 * p2); }
	int quad() const { return sign(y) == 1 || (sign(y) == 0 && sign(x) >= 0); }
	friend bool cmpq(const Pos& a, const Pos& b) { return (a.quad() != b.quad()) ? a.quad() < b.quad() : a / b > 0; }
	bool close(const Pos& p) const { return zero((*this - p).Euc()); }
	friend std::istream& operator >> (std::istream& is, Pos& p) { is >> p.x >> p.y; return is; }
	friend std::ostream& operator << (std::ostream& os, const Pos& p) { os << "(" << p.x << ", " << p.y << ")"; return os; }
} pos[LEN << 3]; const Pos O = Pos(0, 0);
typedef std::vector<Pos> Polygon;
struct Vec {
	ld vy, vx;
	Vec(ld Y = 0, ld X = 0) : vy(Y), vx(X) {}
	bool operator == (const Vec& v) const { return (zero(vy - v.vy) && zero(vx - v.vx)); }
	bool operator < (const Vec& v) const { return zero(vy - v.vy) ? vx < v.vx : vy < v.vy; }
	ld operator * (const Vec& v) const { return vy * v.vy + vx * v.vx; }
	ld operator / (const Vec& v) const { return vy * v.vx - vx * v.vy; }
	Vec operator ~ () const { return { -vx, vy }; }
	Vec& operator *= (const ld& scalar) { vy *= scalar; vx *= scalar; return *this; }
	Vec& operator /= (const ld& scalar) { vy /= scalar; vx /= scalar; return *this; }
}; const Vec Zero = { 0, 0 };
struct Line {//ax + by = c
	Vec s;
	ld c;
	Line(Vec V = Vec(0, 0), ld C = 0) : s(V), c(C) {}
	Line(Vec V = Vec(0, 0), Pos p = Pos(0, 0)) : s(V) { c = s.vy * p.x + s.vx * p.y; }
	Line(Pos ps = Pos(0, 0), Pos pe = Pos(0, 0)) {
		ld dy, dx;
		dy = pe.y - ps.y;
		dx = ps.x - pe.x;
		s = Vec(dy, dx);
		c = dy * ps.x + dx * ps.y;
	}
	bool operator < (const Line& l) const {
		bool f1 = Zero < s;
		bool f2 = Zero < l.s;
		if (f1 != f2) return f1;
		ld CCW = s / l.s;
		return zero(CCW) ? c * hypot(l.s.vy, l.s.vx) < l.c * hypot(s.vy, s.vx) : CCW > 0;
	}
	ld operator / (const Line& l) const { return s / l.s; }
	ld operator * (const Line& l) const { return s * l.s; }
	Line operator + (const ld& scalar) const { return Line(s, c + hypot(s.vy, s.vx) * scalar); }
	Line operator - (const ld& scalar) const { return Line(s, c - hypot(s.vy, s.vx) * scalar); }
	Line operator * (const ld& scalar) const { return Line({ s.vy * scalar, s.vx * scalar }, c * scalar); }
	Line& operator += (const ld& scalar) { c += hypot(s.vy, s.vx) * scalar; return *this; }
	Line& operator -= (const ld& scalar) { c -= hypot(s.vy, s.vx) * scalar; return *this; }
	Line& operator *= (const ld& scalar) { s *= scalar, c *= scalar; return *this; }
	ld dist(const Pos& p) const { return s.vy * p.x + s.vx * p.y; }
	ld above(const Pos& p) const { return s.vy * p.x + s.vx * p.y - c; }
	friend std::ostream& operator << (std::ostream& os, const Line& l) { os << l.s.vy << " " << l.s.vx << " " << l.c; return os; }
};
const Line Xaxis = { { 0, -1 }, 0 };
const Line Yaxis = { { 1, 0 }, 0 };
Line L(const Pos& s, const Pos& e) { return Line(s, e); }
Line rotate90(const Line& l, const Pos& p) { return Line(~l.s, p); }
Pos intersection(const Line& l1, const Line& l2) {
	Vec v1 = l1.s, v2 = l2.s;
	ld det = v1 / v2;
	return {
		(l1.c * v2.vx - l2.c * v1.vx) / det,
		(l2.c * v1.vy - l1.c * v2.vy) / det,
	};
}
ld cross(const Pos& d1, const Pos& d2, const Pos& d3) { return (d2 - d1) / (d3 - d2); }
ld cross(const Pos& d1, const Pos& d2, const Pos& d3, const Pos& d4) { return (d2 - d1) / (d4 - d3); }
int ccw(const Pos& d1, const Pos& d2, const Pos& d3) {
	ld ret = cross(d1, d2, d3);
	return zero(ret) ? 0 : ret > 0 ? 1 : -1;
}
ld dot(const Pos& d1, const Pos& d2, const Pos& d3) { return (d2 - d1) * (d3 - d2); }
ld dot(const Pos& d1, const Pos& d2, const Pos& d3, const Pos& d4) { return (d2 - d1) * (d4 - d3); }
bool on_seg_strong(const Pos& d1, const Pos& d2, const Pos& d3) {
	ld ret = dot(d1, d3, d2);
	return !ccw(d1, d2, d3) && (ret > 0 || zero(ret));
}
bool on_seg_weak(const Pos& d1, const Pos& d2, const Pos& d3) {
	ld ret = dot(d1, d3, d2);
	return !ccw(d1, d2, d3) && ret > 0;
}
Pos intersection(const Pos& p1, const Pos& p2, const Pos& q1, const Pos& q2) {
	ld a1 = cross(q1, q2, p1), a2 = -cross(q1, q2, p2);
	return (p1 * a2 + p2 * a1) / (a1 + a2);
}
ld area(const Polygon& H) {
	ld ret = 0;
	int sz = H.size();
	for (int i = 0; i < sz; i++) ret += H[i] / H[(i + 1) % sz];
	return ret;
}
bool norm(Polygon& H) {
	ld a = area(H);
	if (zero(a)) return 1;
	if (a < 0) std::reverse(H.begin(), H.end());
	return 0;
}
Polygon rotate_and_norm(Polygon B, const int& j0, const Polygon& A, const int& i0, const ld& t, Pos& v) {
	int sz = B.size();
	for (int j = 0; j < sz; j++) B[j] = B[j].rot(t);
	v = A[i0] - B[j0];
	for (int j = 0; j < sz; j++) B[j] += v;
	return B;
}
struct Circle {
	Pos c;
	ld r;
	Circle(Pos C = Pos(0, 0), ld R = 0) : c(C), r(R) {}
	bool operator == (const Circle& C) const { return c == C.c && std::abs(r - C.r) < TOL; }
	bool operator != (const Circle& C) const { return !(*this == C); }
	bool operator > (const Pos& p) const { return r > (c - p).mag(); }
	bool operator >= (const Pos& p) const { return r + TOL > (c - p).mag(); }
	bool operator < (const Pos& p) const { return r < (c - p).mag(); }
	Circle operator + (const Circle& C) const { return { {c.x + C.c.x, c.y + C.c.y}, r + C.r }; }
	Circle operator - (const Circle& C) const { return { {c.x - C.c.x, c.y - C.c.y}, r - C.r }; }
	ld H(const ld& th) const { return sin(th) * c.x + cos(th) * c.y + r; }// coord trans | check right
	ld A() const { return r * r * PI; }
	friend std::istream& operator >> (std::istream& is, Circle& c) { is >> c.c.x >> c.c.y >> c.r; return is; }
	friend std::ostream& operator << (std::ostream& os, const Circle& c) { os << c.c.x << " " << c.c.y << " " << c.r; return os; }
} INVAL = { { 0, 0 }, -1 };
Circle enclose_circle(const Pos& u, const Pos& v) {
	Pos c = (u + v) * .5;
	return Circle(c, (c - u).mag());
}
Circle enclose_circle(const Pos& u, const Pos& v, const Pos& w) {
	Line l1 = rotate90(L(u, v), (u + v) * .5);
	Line l2 = rotate90(L(v, w), (v + w) * .5);
	if (zero(l1 / l2)) return { { 0, 0 }, -1 };
	Pos c = intersection(l1, l2);
	ld r = (c - u).mag();
	return Circle(c, r);
}
Circle minimum_enclose_circle(std::vector<Pos> P) {
	shuffle(P.begin(), P.end(), std::mt19937(0x14004));
	Circle mec = INVAL;
	int sz = P.size();
	for (int i = 0; i < sz; i++) {
		if (mec.r < -1 || mec < P[i]) {
			mec = Circle(P[i], 0);
			for (int j = 0; j <= i; j++) {
				if (mec < P[j]) {
					Circle ans = enclose_circle(P[i], P[j]);
					if (zero(mec.r)) { mec = ans; continue; }
					Circle l = INVAL, r = INVAL;
					for (int k = 0; k <= j; k++) {
						if (ans < P[k]) {
							int CCW = ccw(P[i], P[j], P[k]);
							Circle c = enclose_circle(P[i], P[j], P[k]);
							if (c.r < 0) continue;
							else if (CCW > 0 && (l.r < 0 || cross(P[i], P[j], c.c) > cross(P[i], P[j], l.c))) l = c;
							else if (CCW < 0 && (r.r < 0 || cross(P[i], P[j], c.c) < cross(P[i], P[j], r.c))) r = c;
						}
					}
					if (l.r < 0 && r.r < 0) mec = ans;
					else if (l.r < 0) mec = r;
					else if (r.r < 0) mec = l;
					else mec = l.r < r.r ? l : r;
				}
			}
		}
	}
	return mec;
}
ld minimum_enclose_circle(Polygon A, int i, Polygon B, int j, ld d) {
	Polygon V;
	Pos v = (A[(i + 1) % A.size()] - B[(j + 1) % B.size()]).unit() * d;
	//std::cout << v.mag() << "\n";
	for (Pos& p : B) p += v;
	for (const Pos& p : A) V.push_back(p);
	for (const Pos& p : B) V.push_back(p);
	return minimum_enclose_circle(V).r;
}
ld ternary_search(const Polygon& A, const int& i, const Polygon& B, const int& j) {
	int a = A.size(), b = B.size();
	const Pos& pa = A[(i + 1) % a], & pb = B[(j + 1) % b];
	ld s = 0, e = (pa - pb).mag(), m1, m2, r1 = 0, r2 = 0;
	//std::cout << e << "\n";
	int cnt = 50; while (cnt--) {
		m1 = (s + s + e) / 3;
		m2 = (s + e + e) / 3;
		//std::cout << r1 << " " << r2 << "\n";
		r1 = minimum_enclose_circle(A, i, B, j, m1);
		r2 = minimum_enclose_circle(A, i, B, j, m2);
		if (r1 > r2) s = m1;
		else e = m2;
	}
	return r2;
}
ld ternary_search(const Pos& p0, const Pos& p1, const Pos& p2, const Pos& c, const ld& r) {
	Pos vec, v1, v2;
	auto dist = [&](const ld& t) -> ld {
		Pos s2 = p1 + vec.rot(t);
		ld d = cross(p1, s2, c) / (p1 - s2).mag();
		return r - d;
		};
	vec = (p0 - p1);
	v1 = ~(p0 - p1), v2 = ~(p2 - p1);
	ld s = 0, e = rad(v1, v2), m1, m2, d1, d2;
	int cnt = 25; while (cnt--) {
		m1 = (s + s + e) / 3;
		m2 = (s + e + e) / 3;
		d1 = dist(m1);
		d2 = dist(m2);
		if (sign(d1 < d2)) s = m1;
		else e = m2;
	}
	return (s + e) * .5;
}
ld fit(const Polygon& P, const ld& r) {
	auto dist = [&](const Pos& s1, const Pos& s2, const Pos& c) -> ld {
		ld d = cross(s1, s2, c) / (s1 - s2).mag();
		return r + d;
		};
	int sz = P.size();
	ld ret = INF;
	for (int i = 0; i < sz; i++) {
		for (int j = i + 1; j < sz; j++) {
			ld tmp = INF;
			const Pos& p = P[i], & q = P[j];
			Pos mid = (p + q) * .5;
			Pos vec = p - mid;
			ld h = vec.mag();
			if (sign(h - r) > 0) continue;
			ld w = sqrt(r * r - h * h);
			Pos c1 = mid + ~vec.unit() * w;
			Pos c2 = mid - ~vec.unit() * w;
			for (const Pos& c : { c1, c2 }) {
				bool f = 1;
				for (int k = 0; k < sz; k++) {
					const Pos& p0 = P[(k - 1 + sz) % sz], & p1 = P[k], & p2 = P[(k + 1) % sz];
					assert(ccw(p0, p1, p2) >= 0);
					if (sign((P[k] - c).mag() - r) > 0) { f = 0; break; }
				}
				if (!f) continue;
				for (int k = 0; k < sz; k++) {
					const Pos& p0 = P[(k - 1 + sz) % sz], & p1 = P[k], & p2 = P[(k + 1) % sz];
					assert(ccw(p0, p1, p2) >= 0);
					if (k == i || k == j) {
						assert(eq(r, (P[k] - c).mag()));
						continue;
					}
					//if (sign((P[k] - c).mag() - r) > 0) { tmp = INF; break; }
					//if (eq(r, (p1 - c).mag())) tmp = std::max({ tmp, dist(p0, p1, c1), dist(p1, p2, c) });
					//else if (ccw(p0, p1, c) < 0 && ccw(p1, p2, c) < 0)
					//	tmp = std::max(tmp, ternary_search(p0, p1, p2, c, r));
					//else tmp = std::max({ tmp, dist(p0, p1, c), dist(p1, p2, c) });
					if (ccw(p0, p1, c) < 0 && ccw(p1, p2, c) < 0 && dot(p0, p1, c) > 0 && dot(p2, p1, c) > 0) {
						ld d = r - (c - p1).mag();
						//if (d < 10) {
						//	std::cout << "r:: " << r << "\n";
						//	std::cout << "p0 = " << p0 << " ";
						//	std::cout << "p1 = " << p1 << " ";
						//	std::cout << "p2 = " << p2 << " ";
						//	std::cout << "c = " << c << "\n";
						//	std::cout << "dist = " << (c - p1).mag() << "\n";
						//	std::cout << "d:: " << d << "\n";
						//}
						tmp = std::min(tmp, d);
					}
					else tmp = std::min({ tmp, dist(p0, p1, c), dist(p1, p2, c) });
				}
				ret = std::min(ret, tmp);
			}
		}
	}
	//std::cout << "ret:: " << ret << "\n";
	return ret;
}
bool fit(const Polygon& A, const Polygon& B, const ld& r) {
	ld da = fit(A, r);
	ld db = fit(B, r);
	ld D = r * 2;
	//std::cout << "r:: " << r << " da:: " << da << " db:: " << db << "\n";
	//std::cout << "r*2:: " << r * 2 << "da+db:: " << (da + db) << "\n";
	return sign(D - (da + db)) >= 0 ? 1 : 0;
}
ld bi_search(const Polygon& A, const Polygon& B, ld s, ld e) {
	int cnt = 30; while (cnt--) {
		ld m = (s + e) * .5;
		//std::cout << "m:: " << m << "\n";
		if (fit(A, B, m)) e = m;
		else s = m;
	}
	return (s + e) * .5;
}
bool query() {
	std::cin >> N;
	if (!N) return 0;
	Polygon A(N);
	for (Pos& p : A) std::cin >> p;
	norm(A);
	std::cin >> M;
	Polygon B(M);
	for (Pos& p : B) std::cin >> p;
	norm(B);
	ld ret = INF;
	ld r1 = INF;
	ld ra = minimum_enclose_circle(A).r, rb = minimum_enclose_circle(B).r;
	for (int i = 0; i < N; i++) {
		Pos& I0 = A[i], & I1 = A[(i + 1) % N];
		for (int j = 0; j < M; j++) {
			Pos& J0 = B[j], & J1 = B[(j + 1) % M];
			ld t = rad(J0 - J1, I1 - I0);
			Pos v;
			//std::cout << "FUCK::\n";
			Polygon B2 = rotate_and_norm(B, j, A, i, t, v);
			r1 = std::min(r1, ternary_search(A, i, B2, j));
		}
	}
	//std::cout << "ra :: " << ra << "\n";
	//std::cout << "rb :: " << rb << "\n";
	//std::cout << "r1 :: " << r1 << "\n";
	ld r2 = bi_search(A, B, std::max(ra, rb), r1);
	//std::cout << "r2 :: " << r2 << "\n";
	ret = std::min({ ret, r1, r2 }) * 2;
	//std::cout << "ret:: " << ret << "\n";
	ans.push_back(ret);
	return 1;
}
void solve() {
	std::cin.tie(0)->sync_with_stdio(0);
	std::cout.tie(0);
	std::cout << std::fixed;
	std::cout.precision(15);
	while (query());
	for (const ld& ret : ans) std::cout << ret << "\n";
	return;
}
int main() { solve(); return 0; }//boj20231

/*

40
904 -405
906 -400
395 -616
-16 -989
-10 -992
0 -992
27 -991
50 -990
103 -987
122 -985
130 -984
151 -981
163 -979
228 -966
253 -960
260 -958
312 -942
324 -938
369 -921
392 -912
408 -905
442 -888
467 -875
500 -857
524 -843
527 -841
570 -812
604 -786
618 -775
658 -742
687 -716
715 -688
731 -671
772 -623
797 -591
812 -570
843 -523
876 -463
878 -459
899 -416
40
-923 -266
-817 -489
-724 -604
-635 -711
-626 -718
-536 -780
-352 -889
-334 -897
-205 -934
102 -954
270 -920
357 -891
399 -874
494 -820
513 -809
629 -718
672 -680
756 -591
934 -213
944 -122
954 -4
955 30
939 178
918 261
894 345
865 405
776 565
709 644
478 832
382 877
305 890
202 900
-729 407
-755 393
-841 335
-932 234
-954 50
-956 18
-956 16
-946 -113
0

963.3270026199625

36
510 -524
616 -398
631 -375
675 -289
694 -250
726 -115
728 -73
732 15
732 95
704 213
690 261
653 334
592 434
497 533
452 547
289 518
66 478
-394 388
-638 339
-677 250
-713 163
-724 130
-735 48
-735 -41
-715 -164
-678 -266
-630 -386
-511 -533
-427 -599
-400 -619
-299 -672
-131 -723
-27 -738
110 -722
287 -678
426 -598
21
722 157
721 162
693 258
687 270
665 260
443 -142
381 -622
410 -618
442 -595
478 -567
485 -561
533 -513
599 -429
627 -392
663 -326
689 -271
699 -246
710 -214
722 -162
736 74
734 90
0

5
0 0
3 0
3 1
1 3
0 3
5
0 0
3 0
3 1
1 3
0 3
0

*/
accuracy: 1
time_ms: 7430
memory_kb: 4064
final_rank: 13

code_snippet: #define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <algorithm>
#include <vector>
#include <cmath>
#include <cstring>
#include <cassert>
#include <random>
#include <array>
#include <tuple>
typedef long long ll;
//typedef long double ld;
typedef double ld;
typedef std::pair<int, int> pi;
typedef std::vector<ld> Vld;
const ld INF = 1e17;
const ld TOL = 1e-7;
const ld PI = acos(-1);
const int LEN = 1e3;
inline int sign(const ld& x) { return x < -TOL ? -1 : x > TOL; }
inline bool zero(const ld& x) { return !sign(x); }
inline bool eq(const ld& x, const ld& y) { return zero(x - y); }

Vld ans;
int N, M;
struct Pos {
	ld x, y;
	int i, d;
	Pos(ld X = 0, ld Y = 0) : x(X), y(Y) { i = 0, d = 0; }
	bool operator == (const Pos& p) const { return zero(x - p.x) && zero(y - p.y); }
	bool operator != (const Pos& p) const { return !zero(x - p.x) || !zero(y - p.y); }
	//bool operator < (const Pos& p) const { return zero(x - p.x) ? y < p.y : x < p.x; }
	//bool operator < (const Pos& r) const { return x == r.x ? y == r.y ? d < r.d : y < r.y : x < r.x; }
	bool operator < (const Pos& r) const { return zero(x - r.x) ? zero(y - r.y) ? d < r.d : y < r.y : x < r.x; }
	bool operator <= (const Pos& p) const { return *this < p || *this == p; }
	Pos operator + (const Pos& p) const { return { x + p.x, y + p.y }; }
	Pos operator - (const Pos& p) const { return { x - p.x, y - p.y }; }
	Pos operator * (const ld& scalar) const { return { x * scalar, y * scalar }; }
	Pos operator / (const ld& scalar) const { return { x / scalar, y / scalar }; }
	ld operator * (const Pos& p) const { return x * p.x + y * p.y; }
	ld operator / (const Pos& p) const { return x * p.y - y * p.x; }
	Pos operator ^ (const Pos& p) const { return { x * p.x, y * p.y }; }
	Pos& operator += (const Pos& p) { x += p.x; y += p.y; return *this; }
	Pos& operator -= (const Pos& p) { x -= p.x; y -= p.y; return *this; }
	Pos& operator *= (const ld& scale) { x *= scale; y *= scale; return *this; }
	Pos& operator /= (const ld& scale) { x /= scale; y /= scale; return *this; }
	Pos operator - () const { return { -x, -y }; }
	Pos operator ~ () const { return { -y, x }; }
	Pos operator ! () const { return { y, x }; }
	ld xy() const { return x * y; }
	Pos rot(ld the) const { return { x * cos(the) - y * sin(the), x * sin(the) + y * cos(the) }; }
	ld Euc() const { return x * x + y * y; }
	ld mag() const { return sqrt(Euc()); }
	Pos unit() const { return *this / mag(); }
	ld rad() const { return atan2(y, x); }
	friend ld rad(const Pos& p1, const Pos& p2) { return atan2l(p1 / p2, p1 * p2); }
	int quad() const { return sign(y) == 1 || (sign(y) == 0 && sign(x) >= 0); }
	friend bool cmpq(const Pos& a, const Pos& b) { return (a.quad() != b.quad()) ? a.quad() < b.quad() : a / b > 0; }
	bool close(const Pos& p) const { return zero((*this - p).Euc()); }
	friend std::istream& operator >> (std::istream& is, Pos& p) { is >> p.x >> p.y; return is; }
	friend std::ostream& operator << (std::ostream& os, const Pos& p) { os << "(" << p.x << ", " << p.y << ")"; return os; }
} pos[LEN << 3]; const Pos O = Pos(0, 0);
typedef std::vector<Pos> Polygon;
struct Vec {
	ld vy, vx;
	Vec(ld Y = 0, ld X = 0) : vy(Y), vx(X) {}
	bool operator == (const Vec& v) const { return (zero(vy - v.vy) && zero(vx - v.vx)); }
	bool operator < (const Vec& v) const { return zero(vy - v.vy) ? vx < v.vx : vy < v.vy; }
	ld operator * (const Vec& v) const { return vy * v.vy + vx * v.vx; }
	ld operator / (const Vec& v) const { return vy * v.vx - vx * v.vy; }
	Vec operator ~ () const { return { -vx, vy }; }
	Vec& operator *= (const ld& scalar) { vy *= scalar; vx *= scalar; return *this; }
	Vec& operator /= (const ld& scalar) { vy /= scalar; vx /= scalar; return *this; }
}; const Vec Zero = { 0, 0 };
struct Line {//ax + by = c
	Vec s;
	ld c;
	Line(Vec V = Vec(0, 0), ld C = 0) : s(V), c(C) {}
	Line(Vec V = Vec(0, 0), Pos p = Pos(0, 0)) : s(V) { c = s.vy * p.x + s.vx * p.y; }
	Line(Pos ps = Pos(0, 0), Pos pe = Pos(0, 0)) {
		ld dy, dx;
		dy = pe.y - ps.y;
		dx = ps.x - pe.x;
		s = Vec(dy, dx);
		c = dy * ps.x + dx * ps.y;
	}
	bool operator < (const Line& l) const {
		bool f1 = Zero < s;
		bool f2 = Zero < l.s;
		if (f1 != f2) return f1;
		ld CCW = s / l.s;
		return zero(CCW) ? c * hypot(l.s.vy, l.s.vx) < l.c * hypot(s.vy, s.vx) : CCW > 0;
	}
	ld operator / (const Line& l) const { return s / l.s; }
	ld operator * (const Line& l) const { return s * l.s; }
	Line operator + (const ld& scalar) const { return Line(s, c + hypot(s.vy, s.vx) * scalar); }
	Line operator - (const ld& scalar) const { return Line(s, c - hypot(s.vy, s.vx) * scalar); }
	Line operator * (const ld& scalar) const { return Line({ s.vy * scalar, s.vx * scalar }, c * scalar); }
	Line& operator += (const ld& scalar) { c += hypot(s.vy, s.vx) * scalar; return *this; }
	Line& operator -= (const ld& scalar) { c -= hypot(s.vy, s.vx) * scalar; return *this; }
	Line& operator *= (const ld& scalar) { s *= scalar, c *= scalar; return *this; }
	ld dist(const Pos& p) const { return s.vy * p.x + s.vx * p.y; }
	ld above(const Pos& p) const { return s.vy * p.x + s.vx * p.y - c; }
	friend std::ostream& operator << (std::ostream& os, const Line& l) { os << l.s.vy << " " << l.s.vx << " " << l.c; return os; }
};
const Line Xaxis = { { 0, -1 }, 0 };
const Line Yaxis = { { 1, 0 }, 0 };
Line L(const Pos& s, const Pos& e) { return Line(s, e); }
Line rotate90(const Line& l, const Pos& p) { return Line(~l.s, p); }
Pos intersection(const Line& l1, const Line& l2) {
	Vec v1 = l1.s, v2 = l2.s;
	ld det = v1 / v2;
	return {
		(l1.c * v2.vx - l2.c * v1.vx) / det,
		(l2.c * v1.vy - l1.c * v2.vy) / det,
	};
}
ld cross(const Pos& d1, const Pos& d2, const Pos& d3) { return (d2 - d1) / (d3 - d2); }
ld cross(const Pos& d1, const Pos& d2, const Pos& d3, const Pos& d4) { return (d2 - d1) / (d4 - d3); }
int ccw(const Pos& d1, const Pos& d2, const Pos& d3) {
	ld ret = cross(d1, d2, d3);
	return zero(ret) ? 0 : ret > 0 ? 1 : -1;
}
ld dot(const Pos& d1, const Pos& d2, const Pos& d3) { return (d2 - d1) * (d3 - d2); }
ld dot(const Pos& d1, const Pos& d2, const Pos& d3, const Pos& d4) { return (d2 - d1) * (d4 - d3); }
bool on_seg_strong(const Pos& d1, const Pos& d2, const Pos& d3) {
	ld ret = dot(d1, d3, d2);
	return !ccw(d1, d2, d3) && (ret > 0 || zero(ret));
}
bool on_seg_weak(const Pos& d1, const Pos& d2, const Pos& d3) {
	ld ret = dot(d1, d3, d2);
	return !ccw(d1, d2, d3) && ret > 0;
}
Pos intersection(const Pos& p1, const Pos& p2, const Pos& q1, const Pos& q2) {
	ld a1 = cross(q1, q2, p1), a2 = -cross(q1, q2, p2);
	return (p1 * a2 + p2 * a1) / (a1 + a2);
}
ld area(const Polygon& H) {
	ld ret = 0;
	int sz = H.size();
	for (int i = 0; i < sz; i++) ret += H[i] / H[(i + 1) % sz];
	return ret;
}
bool norm(Polygon& H) {
	ld a = area(H);
	if (zero(a)) return 1;
	if (a < 0) std::reverse(H.begin(), H.end());
	return 0;
}
Polygon rotate_and_norm(Polygon B, const int& j0, const Polygon& A, const int& i0, const ld& t, Pos& v) {
	int sz = B.size();
	for (int j = 0; j < sz; j++) B[j] = B[j].rot(t);
	v = A[i0] - B[j0];
	for (int j = 0; j < sz; j++) B[j] += v;
	return B;
}
struct Circle {
	Pos c;
	ld r;
	Circle(Pos C = Pos(0, 0), ld R = 0) : c(C), r(R) {}
	bool operator == (const Circle& C) const { return c == C.c && std::abs(r - C.r) < TOL; }
	bool operator != (const Circle& C) const { return !(*this == C); }
	bool operator > (const Pos& p) const { return r > (c - p).mag(); }
	bool operator >= (const Pos& p) const { return r + TOL > (c - p).mag(); }
	bool operator < (const Pos& p) const { return r < (c - p).mag(); }
	Circle operator + (const Circle& C) const { return { {c.x + C.c.x, c.y + C.c.y}, r + C.r }; }
	Circle operator - (const Circle& C) const { return { {c.x - C.c.x, c.y - C.c.y}, r - C.r }; }
	ld H(const ld& th) const { return sin(th) * c.x + cos(th) * c.y + r; }// coord trans | check right
	ld A() const { return r * r * PI; }
	friend std::istream& operator >> (std::istream& is, Circle& c) { is >> c.c.x >> c.c.y >> c.r; return is; }
	friend std::ostream& operator << (std::ostream& os, const Circle& c) { os << c.c.x << " " << c.c.y << " " << c.r; return os; }
} INVAL = { { 0, 0 }, -1 };
Circle enclose_circle(const Pos& u, const Pos& v) {
	Pos c = (u + v) * .5;
	return Circle(c, (c - u).mag());
}
Circle enclose_circle(const Pos& u, const Pos& v, const Pos& w) {
	Line l1 = rotate90(L(u, v), (u + v) * .5);
	Line l2 = rotate90(L(v, w), (v + w) * .5);
	if (zero(l1 / l2)) return { { 0, 0 }, -1 };
	Pos c = intersection(l1, l2);
	ld r = (c - u).mag();
	return Circle(c, r);
}
Circle minimum_enclose_circle(std::vector<Pos> P) {
	shuffle(P.begin(), P.end(), std::mt19937(0x14004));
	Circle mec = INVAL;
	int sz = P.size();
	for (int i = 0; i < sz; i++) {
		if (mec.r < -1 || mec < P[i]) {
			mec = Circle(P[i], 0);
			for (int j = 0; j <= i; j++) {
				if (mec < P[j]) {
					Circle ans = enclose_circle(P[i], P[j]);
					if (zero(mec.r)) { mec = ans; continue; }
					Circle l = INVAL, r = INVAL;
					for (int k = 0; k <= j; k++) {
						if (ans < P[k]) {
							int CCW = ccw(P[i], P[j], P[k]);
							Circle c = enclose_circle(P[i], P[j], P[k]);
							if (c.r < 0) continue;
							else if (CCW > 0 && (l.r < 0 || cross(P[i], P[j], c.c) > cross(P[i], P[j], l.c))) l = c;
							else if (CCW < 0 && (r.r < 0 || cross(P[i], P[j], c.c) < cross(P[i], P[j], r.c))) r = c;
						}
					}
					if (l.r < 0 && r.r < 0) mec = ans;
					else if (l.r < 0) mec = r;
					else if (r.r < 0) mec = l;
					else mec = l.r < r.r ? l : r;
				}
			}
		}
	}
	return mec;
}
ld minimum_enclose_circle(Polygon A, int i, Polygon B, int j, ld d) {
	Polygon V;
	Pos v = (A[(i + 1) % A.size()] - B[(j + 1) % B.size()]).unit() * d;
	//std::cout << v.mag() << "\n";
	for (Pos& p : B) p += v;
	for (const Pos& p : A) V.push_back(p);
	for (const Pos& p : B) V.push_back(p);
	return minimum_enclose_circle(V).r;
}
ld ternary_search(const Polygon& A, const int& i, const Polygon& B, const int& j) {
	int a = A.size(), b = B.size();
	const Pos& pa = A[(i + 1) % a], & pb = B[(j + 1) % b];
	ld s = 0, e = (pa - pb).mag(), m1, m2, r1 = 0, r2 = 0;
	//std::cout << e << "\n";
	int cnt = 50; while (cnt--) {
		m1 = (s + s + e) / 3;
		m2 = (s + e + e) / 3;
		//std::cout << r1 << " " << r2 << "\n";
		r1 = minimum_enclose_circle(A, i, B, j, m1);
		r2 = minimum_enclose_circle(A, i, B, j, m2);
		if (r1 > r2) s = m1;
		else e = m2;
	}
	return r2;
}
ld ternary_search(const Pos& p0, const Pos& p1, const Pos& p2, const Pos& c, const ld& r) {
	Pos vec, v1, v2;
	auto dist = [&](const ld& t) -> ld {
		Pos s2 = p1 + vec.rot(t);
		ld d = cross(p1, s2, c) / (p1 - s2).mag();
		return r - d;
		};
	vec = (p0 - p1);
	v1 = ~(p0 - p1), v2 = ~(p2 - p1);
	ld s = 0, e = rad(v1, v2), m1, m2, d1, d2;
	int cnt = 30; while (cnt--) {
		m1 = (s + s + e) / 3;
		m2 = (s + e + e) / 3;
		d1 = dist(m1);
		d2 = dist(m2);
		if (sign(d1 < d2)) s = m1;
		else e = m2;
	}
	return (s + e) * .5;
}
ld fit(const Polygon& P, const ld& r) {
	auto dist = [&](const Pos& s1, const Pos& s2, const Pos& c) -> ld {
		ld d = cross(s1, s2, c) / (s1 - s2).mag();
		return r + d;
		};
	int sz = P.size();
	ld ret = INF;
	for (int i = 0; i < sz; i++) {
		for (int j = i + 1; j < sz; j++) {
			ld tmp = INF;
			const Pos& p = P[i], & q = P[j];
			Pos mid = (p + q) * .5;
			Pos vec = p - mid;
			ld h = vec.mag();
			if (sign(h - r) > 0) continue;
			ld w = sqrt(r * r - h * h);
			Pos c1 = mid + ~vec.unit() * w;
			Pos c2 = mid - ~vec.unit() * w;
			for (const Pos& c : { c1, c2 }) {
				bool f = 1;
				for (int k = 0; k < sz; k++) {
					const Pos& p0 = P[(k - 1 + sz) % sz], & p1 = P[k], & p2 = P[(k + 1) % sz];
					assert(ccw(p0, p1, p2) >= 0);
					if (sign((P[k] - c).mag() - r) > 0) { f = 0; break; }
				}
				if (!f) continue;
				for (int k = 0; k < sz; k++) {
					const Pos& p0 = P[(k - 1 + sz) % sz], & p1 = P[k], & p2 = P[(k + 1) % sz];
					assert(ccw(p0, p1, p2) >= 0);
					if (k == i || k == j) {
						assert(eq(r, (P[k] - c).mag()));
						continue;
					}
					//if (sign((P[k] - c).mag() - r) > 0) { tmp = INF; break; }
					//if (eq(r, (p1 - c).mag())) tmp = std::max({ tmp, dist(p0, p1, c1), dist(p1, p2, c) });
					//else if (ccw(p0, p1, c) < 0 && ccw(p1, p2, c) < 0)
					//	tmp = std::max(tmp, ternary_search(p0, p1, p2, c, r));
					//else tmp = std::max({ tmp, dist(p0, p1, c), dist(p1, p2, c) });
					if (ccw(p0, p1, c) < 0 && ccw(p1, p2, c) < 0 && dot(p0, p1, c) > 0 && dot(p2, p1, c) > 0) {
						ld d = r - (c - p1).mag();
						//if (d < 10) {
						//	//std::cout << "r:: " << r << "\n";
						//	//std::cout << "p0 = " << p0 << " ";
						//	//std::cout << "p1 = " << p1 << " ";
						//	//std::cout << "p2 = " << p2 << " ";
						//	//std::cout << "c = " << c << "\n";
						//	//std::cout << "dist = " << (c - p1).mag() << "\n";
						//	//std::cout << "d:: " << d << "\n";
						//}
						tmp = std::min(tmp, d);
					}
					else tmp = std::min({ tmp, dist(p0, p1, c), dist(p1, p2, c) });
				}


				ret = std::min(ret, tmp);
			}
		}
	}
	//std::cout << "ret:: " << ret << "\n";
	return ret;
}
bool fit(const Polygon& A, const Polygon& B, const ld& r) {
	ld da = fit(A, r);
	ld db = fit(B, r);
	ld D = r * 2;
	//std::cout << "r:: " << r << " da:: " << da << " db:: " << db << "\n";
	//std::cout << "r*2:: " << r * 2 << "da+db:: " << (da + db) << "\n";
	return sign(D - (da + db)) >= 0 ? 1 : 0;
}
ld bi_search(const Polygon& A, const Polygon& B, ld s, ld e) {
	int cnt = 30; while (cnt--) {
		ld m = (s + e) * .5;
		//std::cout << "m:: " << m << "\n";
		if (fit(A, B, m)) e = m;
		else s = m;
	}
	return (s + e) * .5;
}
bool query() {
	std::cin >> N;
	if (!N) return 0;
	Polygon A(N);
	for (Pos& p : A) std::cin >> p;
	norm(A);
	std::cin >> M;
	Polygon B(M);
	for (Pos& p : B) std::cin >> p;
	norm(B);
	ld ret = INF;
	ld r1 = INF;
	ld ra = minimum_enclose_circle(A).r, rb = minimum_enclose_circle(B).r;
	for (int i = 0; i < N; i++) {
		Pos& I0 = A[i], & I1 = A[(i + 1) % N];
		for (int j = 0; j < M; j++) {
			Pos& J0 = B[j], & J1 = B[(j + 1) % M];
			ld t = rad(J0 - J1, I1 - I0);
			Pos v;
			//std::cout << "FUCK::\n";
			Polygon B2 = rotate_and_norm(B, j, A, i, t, v);
			r1 = std::min(r1, ternary_search(A, i, B2, j));
		}
	}
	//std::cout << "ra :: " << ra << "\n";
	//std::cout << "rb :: " << rb << "\n";
	//std::cout << "r1 :: " << r1 << "\n";
	ld r2 = bi_search(A, B, std::max(ra, rb), r1);
	//std::cout << "r2 :: " << r2 << "\n";
	ret = std::min({ ret, r1, r2 }) * 2;
	//std::cout << "ret:: " << ret << "\n";
	ans.push_back(ret);
	return 1;
}
void solve() {
	std::cin.tie(0)->sync_with_stdio(0);
	std::cout.tie(0);
	std::cout << std::fixed;
	std::cout.precision(15);
	while (query());
	for (const ld& ret : ans) std::cout << ret << "\n";
	return;
}
int main() { solve(); return 0; }//boj20231

/*

40
904 -405
906 -400
395 -616
-16 -989
-10 -992
0 -992
27 -991
50 -990
103 -987
122 -985
130 -984
151 -981
163 -979
228 -966
253 -960
260 -958
312 -942
324 -938
369 -921
392 -912
408 -905
442 -888
467 -875
500 -857
524 -843
527 -841
570 -812
604 -786
618 -775
658 -742
687 -716
715 -688
731 -671
772 -623
797 -591
812 -570
843 -523
876 -463
878 -459
899 -416
40
-923 -266
-817 -489
-724 -604
-635 -711
-626 -718
-536 -780
-352 -889
-334 -897
-205 -934
102 -954
270 -920
357 -891
399 -874
494 -820
513 -809
629 -718
672 -680
756 -591
934 -213
944 -122
954 -4
955 30
939 178
918 261
894 345
865 405
776 565
709 644
478 832
382 877
305 890
202 900
-729 407
-755 393
-841 335
-932 234
-954 50
-956 18
-956 16
-946 -113
0

963.3270026199625

36
510 -524
616 -398
631 -375
675 -289
694 -250
726 -115
728 -73
732 15
732 95
704 213
690 261
653 334
592 434
497 533
452 547
289 518
66 478
-394 388
-638 339
-677 250
-713 163
-724 130
-735 48
-735 -41
-715 -164
-678 -266
-630 -386
-511 -533
-427 -599
-400 -619
-299 -672
-131 -723
-27 -738
110 -722
287 -678
426 -598
21
722 157
721 162
693 258
687 270
665 260
443 -142
381 -622
410 -618
442 -595
478 -567
485 -561
533 -513
599 -429
627 -392
663 -326
689 -271
699 -246
710 -214
722 -162
736 74
734 90
0

5
0 0
3 0
3 1
1 3
0 3
5
0 0
3 0
3 1
1 3
0 3
0

*/
accuracy: 1
time_ms: 7440
memory_kb: 4080
final_rank: 14

code_snippet: #include<bits/stdc++.h>
using namespace std;

namespace noya2 {

template <typename T, typename U>
ostream &operator<<(ostream &os, const pair<T, U> &p){
    os << p.first << " " << p.second;
    return os;
}
template <typename T, typename U>
istream &operator>>(istream &is, pair<T, U> &p){
    is >> p.first >> p.second;
    return is;
}

template <typename T>
ostream &operator<<(ostream &os, const vector<T> &v){
    int s = (int)v.size();
    for (int i = 0; i < s; i++) os << (i ? " " : "") << v[i];
    return os;
}
template <typename T>
istream &operator>>(istream &is, vector<T> &v){
    for (auto &x : v) is >> x;
    return is;
}

void in() {}
template <typename T, class... U>
void in(T &t, U &...u){
    cin >> t;
    in(u...);
}

void out() { cout << "\n"; }
template <typename T, class... U, char sep = ' '>
void out(const T &t, const U &...u){
    cout << t;
    if (sizeof...(u)) cout << sep;
    out(u...);
}

template<typename T>
void out(const vector<vector<T>> &vv){
    int s = (int)vv.size();
    for (int i = 0; i < s; i++) out(vv[i]);
}

struct IoSetup {
    IoSetup(){
        cin.tie(nullptr);
        ios::sync_with_stdio(false);
        cout << fixed << setprecision(15);
        cerr << fixed << setprecision(7);
    }
} iosetup_noya2;

const int iinf = 1'000'000'007;
const long long linf = 2'000'000'000'000'000'000LL;
const long long mod998 =  998244353;
const long long mod107 = 1000000007;
const long double pi = 3.14159265358979323;
const vector<int> dx = {0,1,0,-1,1,1,-1,-1};
const vector<int> dy = {1,0,-1,0,1,-1,-1,1};
const string ALP = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
const string alp = "abcdefghijklmnopqrstuvwxyz";
const string NUM = "0123456789";

void yes(){ cout << "Yes\n"; }
void no(){ cout << "No\n"; }
void YES(){ cout << "YES\n"; }
void NO(){ cout << "NO\n"; }
void yn(bool t){ t ? yes() : no(); }
void YN(bool t){ t ? YES() : NO(); }


unsigned long long inner_binary_gcd(unsigned long long a, unsigned long long b){
    if (a == 0 || b == 0) return a + b;
    int n = __builtin_ctzll(a); a >>= n;
    int m = __builtin_ctzll(b); b >>= m;
    while (a != b) {
        int mm = __builtin_ctzll(a - b);
        bool f = a > b;
        unsigned long long c = f ? a : b;
        b = f ? b : a;
        a = (c - b) >> mm;
    }
    return a << min(n, m);
}

template<typename T> T gcd_fast(T a, T b){ return static_cast<T>(inner_binary_gcd(abs(a),abs(b))); }

long long sqrt_fast(long long n) {
    if (n <= 0) return 0;
    long long x = sqrt(n);
    while ((x + 1) * (x + 1) <= n) x++;
    while (x * x > n) x--;
    return x;
}

template<typename T> T floor_div(const T n, const T d) {
    assert(d != 0);
    return n / d - static_cast<T>((n ^ d) < 0 && n % d != 0);
}

template<typename T> T ceil_div(const T n, const T d) {
    assert(d != 0);
    return n / d + static_cast<T>((n ^ d) >= 0 && n % d != 0);
}

template<typename T> void uniq(vector<T> &v){
    sort(v.begin(),v.end());
    v.erase(unique(v.begin(),v.end()),v.end());
}

template <typename T, typename U> inline bool chmin(T &x, U y) { return (y < x) ? (x = y, true) : false; }

template <typename T, typename U> inline bool chmax(T &x, U y) { return (x < y) ? (x = y, true) : false; }

template<typename T> inline bool range(T l, T x, T r){ return l <= x && x < r; }

} // namespace noya2

#define rep(i,n) for (int i = 0; i < (int)(n); i++)
#define repp(i,m,n) for (int i = (m); i < (int)(n); i++)
#define reb(i,n) for (int i = (int)(n-1); i >= 0; i--)
#define all(v) (v).begin(),(v).end()

using ll = long long;
using ld = long double;
using uint = unsigned int;
using ull = unsigned long long;
using pii = pair<int,int>;
using pll = pair<ll,ll>;
using pil = pair<int,ll>;
using pli = pair<ll,int>;

namespace noya2{

/*　~ (. _________ . /)　*/

}

using namespace noya2;

#include <type_traits>
#include <cmath>
#include <algorithm>
#include <vector>
#include <iostream>
#include <numeric>
#include <cassert>



template<typename Float>
constexpr Float EPS = Float{1e-6};

template<typename Float>
constexpr int sign(const Float &x, Float eps = EPS<Float>){
    return (x < -eps ? -1 : x > eps ? 1 : 0);
}

template<typename Float>
struct point {
    Float x, y;
    point () {}
    point (Float _x, Float _y) : x(_x), y(_y) {}
    point &operator+=(const point &r){
        x += r.x;
        y += r.y;
        return *this;
    }
    point &operator-=(const point &r){
        x -= r.x;
        y -= r.y;
        return *this;
    }
    point operator+() const {
        return *this;
    }
    point operator-() const {
        x = -x;
        y = -y;
        return *this;
    }
    point &operator*=(const Float &a){
        x *= a;
        y *= a;
        return *this;
    }
	point &operator/=(const Float &a){
        x /= a;
        y /= a;
        return *this;
    }
    friend point operator+(const point& lhs, const point& rhs){
        return point(lhs) += rhs;
    }
    friend point operator-(const point& lhs, const point& rhs){
        return point(lhs) -= rhs;
    }
    friend point operator*(const point& lhs, const Float& a){
        return point(lhs) *= a;
    }
    friend point operator*(const Float& a, const point& rhs){
        return point(rhs) *= a;
    }
	friend point operator/(const point& lhs, const Float& a){
        return point(lhs) /= a;
    }
    friend std::ostream &operator<<(std::ostream &os, const point& p){
        return os << p.x << ' ' << p.y;
    }
    friend std::istream &operator>>(std::istream &is, point &a){
        Float _x, _y; is >> _x >> _y;
        a = point(_x, _y);
        return (is);
    }
    friend Float norm(const point &a) {
        return a.x*a.x + a.y*a.y;
    }
    friend Float dot(const point &a, const point &b){
        return a.x*b.x + a.y*b.y;
    }
    friend Float cross(const point &a, const point &b){
        return a.x*b.y - a.y*b.x;
    }
	friend point rot90(const point &a){
		return point(-a.y, a.x);
	}
    friend point rot(const point &a, const Float rad){
        using std::cos, std::sin;
        Float cosrad = cos(rad);
        Float sinrad = sin(rad);
        return point(a.x * cosrad - a.y * sinrad, a.x * sinrad + a.y * cosrad);
    }
    friend Float abs(const point &a){
        using std::sqrt;
        return sqrt(norm(a));
    }

    friend int quadrant_atan2(const point &a){
        // not origin point
        // ceil ( atan2(y,x) / (pi/2) )
		int signx = sign(a.x);
		int signy = sign(a.y);
		if (signx <= 0 && signy <  0) return -1;
		if (signx >  0 && signy <= 0) return  0;
		if (signx >= 0 && signy >  0) return  1;
		if (signx <  0 && signy >= 0) return  2;
        // origin point x == 0 && y == 0
        return 0;
    }

    friend int sign_cross(const point &a, const point &b){
        using std::abs;
        return sign(cross(a, b), EPS<Float> * (abs(a.x) + abs(a.y) + abs(b.x) + abs(b.y)));
    }

    friend int sign_dot(const point &a, const point &b){
        using std::abs;
        return sign(dot(a, b), EPS<Float> * (abs(a.x) + abs(a.y) + abs(b.x) + abs(b.y)));
    }

	friend int ccw(const point &a, point b, point c){
		b -= a;
		c -= a;
		int signcr = sign_cross(b, c);
		if (signcr > 0){
			// ccw       
			//           c
			// a --> b 
			return 1;
		}
		if (signcr < 0){
			// cw
			// a --> b
			//           c
			return -1;
		}
		if (sign_dot(b, c) < 0){
			// c  a --> b
			return 2;
		}
		if (norm(b) < norm(c)){
			// a --> b   c
			return -2;
		}
		// a - b -> c
		return 0;
	}
    friend bool has_common_point(const point &a, const point &b){
        return sign(a.x - b.x) == 0 && sign(a.y - b.y) == 0;
    }
};

template<typename Float>
struct arg_less {
    constexpr bool operator()(const point<Float> &l, const point<Float> &r){
        using std::atan2;
        return atan2(l.y, l.x) < atan2(r.y, r.x);
    }
};

template<typename Float>
void arg_sort(std::vector<point<Float>> &a){
	std::sort(a.begin(), a.end(), arg_less<Float>{});
}


template<typename Point>
std::vector<int> upper_convex_hull_index(const std::vector<Point> &a){
	if (a.empty()) return {};
	std::vector<int> ids(a.size());
    std::iota(ids.begin(), ids.end(), 0);
	std::sort(ids.begin(), ids.end(), [&](int l, int r){
		return a[l] < a[r];
	});
	std::vector<int> st(a.size());
	int ptr = 0;
	for (int i : ids){
		if (ptr >= 1 && a[st[ptr-1]].x == a[i].x) ptr--;
		while (ptr >= 2){
			int c = st[ptr-1];
			int p = st[ptr-2];
			if (sign_cross(a[i] - a[c], a[c] - a[p]) > 0){
				break;
			}
			ptr--;
		}
		st[ptr++] = i;
	}
	st.resize(ptr);
	return st;
}

template<typename Float>
std::vector<int> lower_convex_hull_index(const std::vector<point<Float>> &a){
	if (a.empty()) return {};
	std::vector<int> ids(a.size());
    std::iota(ids.begin(), ids.end(), 0);
	std::sort(ids.begin(), ids.end(), [&](int l, int r){
		return a[l] < a[r];
	});
	std::vector<int> st(a.size());
	int ptr = 0;
	for (int i : ids){
		if (ptr >= 1 && a[st[ptr-1]].x == a[i].x) continue;
		while (ptr >= 2){
			int c = st[ptr-1];
			int p = st[ptr-2];
			if (sign_cross(a[c] - a[p], a[i] - a[c]) > 0){
				break;
			}
			ptr--;
		}
		st[ptr++] = i;
	}
	st.resize(ptr);
	return st;
}

template<typename Point>
std::vector<int> convex_hull_index(const std::vector<Point> &a){
	if (a.empty()) return {};
	auto upper = upper_convex_hull_index(a);
	auto lower = lower_convex_hull_index(a);
	if (upper.size() == 1u){
		// lower.size() == 1u
		if (a[upper.front()] == a[lower.front()]){
			return {upper.front()};
		}
		return {lower.front(), upper.front()};
	}
	if (a[upper.back()] == a[lower.back()]){
		lower.pop_back();
	}
	lower.insert(lower.end(), upper.rbegin(), upper.rend());
	if (a[upper.front()] == a[lower.front()]) lower.pop_back();
	return lower;
}


template<typename Float>
struct line {
	point<Float> end0, end1;
    line () {}
	line (const point<Float> &_end0, const point<Float> &_end1) : end0(_end0), end1(_end1) {
		// assert(end0 != end1);
	}
	point<Float> direction() const {
		return end1 - end0;
	}
    friend bool is_parallel(const line &a, const line &b){
        return sign_cross(a.direction(), b.direction()) == 0;
    }
    friend bool is_orthgonal(const line &a, const line &b){
        return sign_dot(a.direction(), b.direction()) == 0;
    }
	friend bool has_common_point(const line &a, const point<Float> &b){
		return sign(cross(a.direction(), b - a.end0)) == 0;
	}
	friend bool has_common_point(const line &a, const line &b){
		return !is_parallel(a, b) || has_common_point(a, b.end0);
	}
	friend point<Float> common_point(const line &a, const line &b){
		// assert(has_common_point(a, b));
		if (is_parallel(a, b)){
			return a.end0;
		}
		return a.end0 + a.direction() * cross(b.end0 - a.end0, b.end1 - b.end0) / cross(a.direction(), b.direction());
	}
	friend point<Float> projection(const line &a, const point<Float> &b){
		auto dir = a.direction();
		return a.end0 + dir * (dot(dir, b - a.end0) / norm(dir));
	}
	friend point<Float> reflection(const line &a, const point<Float> &b){
		auto prj = projection(a, b);
		return prj + prj - b;
	}
};


template<typename Float>
struct segment {
	point<Float> end0, end1;
    segment () {}
	segment (const point<Float> &_end0, const point<Float> &_end1) : end0(_end0), end1(_end1) {
		// assert(end0 != end1);
	}
	point<Float> direction() const {
		return end1 - end0;
	}
    friend bool is_parallel(const segment &a, const segment &b){
        return sign_cross(a.direction(), b.direction()) == 0;
    }
    friend bool is_orthgonal(const segment &a, const segment &b){
        return sign_dot(a.direction(), b.direction()) == 0;
    }
	friend bool has_common_point(const segment &a, const segment &b){
		return ccw(a.end0, a.end1, b.end0) * ccw(a.end0, a.end1, b.end1) <= 0
			&& ccw(b.end0, b.end1, a.end0) * ccw(b.end0, b.end1, a.end1) <= 0;
	}
	friend bool has_common_point(const segment &a, const point<Float> &b){
		return ccw(a.end0, a.end1, b) == 0;
	}
	friend point<Float> common_point(const segment &a, const segment &b){
		// assert(has_common_point(a, b));
		if (is_parallel(a, b)){
			if (has_common_point(a, b.end0)){
				return b.end0;
			}
			if (has_common_point(a, b.end1)){
				return b.end1;
			}
			return a.end0;
		}
		return a.end0 + a.direction() * cross(b.end0 - a.end0, b.end1 - b.end0) / cross(a.direction(), b.direction());
	}
	line<Float> as_line() const {
		return line<Float>(end0, end1);
	}
};

template<typename Float>
struct circle {
    point<Float> center;
    Float radius;
    circle () {}
    circle (const point<Float> &_center, const Float &_radius) : center(_center), radius(_radius) {
        assert(sign(radius) >= 0);
    }
    friend int num_of_common_tangents(const circle &a, const circle &b){
        if (has_common_point(a.center, b.center) && sign(a.radius - b.radius) == 0){
            return 5; // infty
        }
        Float d = abs(a.center - b.center);
        Float r1 = a.radius, r2 = b.radius;
        int sumsign = sign(d - (r1 + r2));
        if (sumsign >= 0) return sumsign + 3;
        using std::abs;
        int diffsign = sign(d - abs(r1 - r2));
        return diffsign + 1;
    }
    friend bool has_common_point(const circle &a, const circle &b){
        int cnt = num_of_common_tangents(a, b);
        return cnt == 1 || cnt == 2 || cnt == 3 || cnt == 5;
    }
    friend bool has_common_point(const circle &c, const line<Float> &l){
        point<Float> p = reflection(l, c.center);
        Float d = abs(c.center, p);
        return sign(c.radius - d) >= 0;
    }
    friend bool has_common_point(const circle &c, const segment<Float> &s){
        // return std::ranges::any_of(common_points(c, s.as_line()), [&](auto p){
        //     return has_common_point(s, p);
        // });
        return false;
    }
    friend bool has_common_point(const circle &c, const point<Float> &p){
        return sign(abs(p - c.center) - c.radius) == 0;
    }
    friend std::vector<point<Float>> common_points(const circle &a, const circle &b){
        int cnt = num_of_common_tangents(a, b);
        assert(cnt != 5); // cannot be same circle
        if (cnt == 0 || cnt == 4){
            return {};
        }
        Float d = abs(a.center - b.center);
        Float x = (d*d + a.radius*a.radius - b.radius*b.radius) / (d + d);
        point<Float> p = a.center + (b.center - a.center) * x / d;
        if (cnt == 1 || cnt == 3 || sign(a.radius - x) <= 0){
            return {p};
        }
        point<Float> v = rot90(b.center - a.center);
        using std::sqrt;
        v *= sqrt(a.radius*a.radius - x*x) / abs(v);
        return {p + v, p - v};
    }
    friend std::vector<point<Float>> common_points(const circle &c, const line<Float> &l) {
        point<Float> p = reflection(l, c.center);
        Float d = abs(c.center, p);
        int cnt = sign(c.radius - d) + 1;
        if (cnt == 0){
            return {};
        }
        if (cnt == 1 || sign(c.radius - d) <= 0){
            return {p};
        }
        point<Float> v = l.direction();
        using std::sqrt;
        v *= sqrt(c.radius*c.radius - d*d) / abs(v);
        return {p + v, p - v};
    }
};


template<>
constexpr ld EPS<ld> = 1e-8;

using pt = point<ld>;
using cr = circle<ld>;

bool includes(const vector<pt> &a, ld r, ld ylow){
    int n = a.size();
    pt ga(0,0);
    rep(i,n) ga += a[i];
    ga /= n;
    rep(i,n) rep(j,n){
        if (i == j) continue;
        pt mid = (a[i] + a[j]) / 2;
        ld d = abs(a[i] - a[j]) / 2;
        if (sign(d - r) >= 0) continue;
        pt ctr = mid + rot90(mid - a[i]) * sqrt(r*r-d*d) / d;
        bool ok = true;
        rep(k,n){
            if (sign(abs(a[k] - ctr) - r) <= 0) continue;
            ok = false;
            break;
        }
        if (!ok) continue;
        rep(k,n){
            line<ld> l(a[k],a[k == n-1 ? 0 : k+1]);
            pt pr = projection(l, ctr);
            int dirg = ccw(l.end0, l.end1, ga);
            int dirc = ccw(l.end0, l.end1, ctr);
            ld cur = r;
            if (dirg == dirc){
                cur += abs(pr - ctr);
            }
            else {
                cur -= abs(pr - ctr);
            }
            if (sign(r - cur - ylow) >= 0){
                return true;
            }
        }
        rep(k,n){
            if (sign(abs(ctr - a[k])) == 0){
                if (sign(ylow) <= 0){
                    return true;
                }
                continue;
            }
            line<ld> l(a[k], a[k] + rot90(a[k] - ctr));
            int dirg = ccw(l.end0, l.end1, ga);
            int dirc = ccw(l.end0, l.end1, ctr);
            if (dirg == dirc) continue;
            ld cur = r - abs(projection(l, ctr) - ctr);
            if (sign(r - cur - ylow) < 0) continue;
            bool okk = true;
            rep(kk,n){
                if (ccw(l.end0, l.end1, a[kk]) != dirc) continue;
                okk = false;
                break;
            }
            if (okk) return true;
        }
    }
    rep(i,n){
        pt dir = (a[i == n-1 ? 0 : i+1] - a[i]);
        dir /= abs(dir);
        ld xl = -1e9, xr = 1e9;
        rep(j,n){
            pt v = a[j] - a[i];
            ld h = abs(cross(v, dir));
            if (sign(ylow + h - r) >= 0){
                xl = 1;
                xr = -1;
                break;
            }
            ld geta = dot(v, dir);
            ld y = ylow + h;
            ld w = sqrt(r*r - y*y);
            chmax(xl,-w-geta);
            chmin(xr,+w-geta);
        }
        if (sign(xl - xr) <= 0){
            return true;
        }
    }
    return false;
}

ld height(const vector<pt> &a, ld r){
    int n = a.size();
    vector<cr> cs(n);
    rep(i,n){
        cs[i] = cr(a[i],r);
    }
    auto check = [&](pt p){
        bool ok = true;
        rep(k,n){
            if (sign(abs(a[k] - p) - r) <= 0) continue;
            ok = false;
            break;
        }
        return ok;
    };
    bool inc = false;
    rep(i,n-1) repp(j,i+1,n){
        if (inc) break;
        for (auto p : common_points(cs[i], cs[j])){
            if (check(p)){
                inc = true;
                break;
            }
        }
    }
    rep(i,n){
        if (check(a[i])){
            inc = true;
            break;
        }
    }
    if (!inc){
        return r*10;
    }
    ld le = 0, ri = 2*r;
    rep(tt,60){
        ld md = (le + ri) / 2;
        if (includes(a, r, r - md)){
            ri = md;
        }
        else {
            le = md;
        }
    }
    return ri;
}

void solve(int n){
    vector<pt> a(n); in(a);
    int m; in(m);
    vector<pt> b(m); in(b);
    ld le = 0, ri = 1e9;
    rep(tt,60){
        ld md = (le + ri) / 2;
        ld ha = height(a, md);
        ld hb = height(b, md);
        if (ha + hb <= md + md){
            ri = md;
        }
        else {
            le = md;
        }
    }
    out(ri*2);
}

int main(){
    while (true){
        int n; in(n);
        if (n == 0) break;
        solve(n);
    }
}
accuracy: 1
time_ms: 7890
memory_kb: 3560
final_rank: 12

code_snippet: #include <cmath>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;

class point2d {
public:
	double x, y;
	point2d() : x(0.0), y(0.0) {};
	point2d(double x_, double y_) : x(x_), y(y_) {};
	point2d& operator+=(const point2d& p) { x += p.x; y += p.y; return (*this); }
	point2d& operator-=(const point2d& p) { x -= p.x; y -= p.y; return (*this); }
	point2d& operator*=(double v) { x *= v; y *= v; return (*this); }
	point2d operator+(const point2d& p) const { return point2d(*this) += p; }
	point2d operator-(const point2d& p) const { return point2d(*this) -= p; }
	point2d operator*(double v) const { return point2d(*this) *= v; }
	double abs() const {
		return sqrt(x * x + y * y);
	}
	double dot(const point2d& p) const {
		return x * p.x + y * p.y;
	}
};

const double pi = acos(-1.0);

// Q. Can the polygon be placed in range x^2 + y^2 <= R, y >= YL ???
bool check(int N, const vector<point2d>& P, double R, double YL, const vector<vector<vector<point2d> > >& anglist) {
	// Case #1. Two vertices in line y = YL
	for (int i = 0; i < N; i++) {
		double l = -1.0e+9, r = +1.0e+9;
		for (int j = 0; j < N; j++) {
			point2d subp = point2d(0, YL) + anglist[i][(i + 1) % N][j];
			if (subp.y >= R) {
				l = +1.0e+9;
				r = -1.0e+9;
			}
			else {
				double w = sqrt(R * R - subp.y * subp.y);
				l = max(l, -w - subp.x);
				r = min(r, +w - subp.x);
			}
		}
		if (l < r) {
			return true;
		}
	}
	// Case #2. Two vertices in circle's circumference
	for (int i = 0; i < N; i++) {
		for (int j = 0; j < N; j++) {
			if (i == j || (P[j] - P[i]).abs() >= 2 * R) {
				continue;
			}
			double elen = (P[j] - P[i]).abs();
			double subh = sqrt(R * R - elen * elen / 4);
			double l1 = 0.0, r1 = 2 * pi;
			double l2 = 0.0, r2 = 2 * pi;
			bool valid = true;
			for (int k = 0; k < N; k++) {
				point2d subp = point2d(-elen / 2, -subh) + anglist[i][j][k];
				double d = subp.abs();
				if (d >= R + 1.0e-7 || (YL >= 0 && d <= YL)) {
					valid = false;
					break;
				}
				double phi = atan2(subp.y, subp.x);
				if (d > -YL) {
					double g = asin(YL / d);
					double cl = g - phi;
					double cr = (pi - g) - phi;
					while (cl < 0.0) cl += 2 * pi;
					while (cl >= 2 * pi) cl -= 2 * pi;
					while (cr < 0.0) cr += 2 * pi;
					while (cr >= 2 * pi) cr -= 2 * pi;
					if (cl <= cr) {
						l1 = max(l1, cl);
						r1 = min(r1, cr);
					}
					else {
						l2 = max(l2, cl);
						r2 = min(r2, cr);
					}
					if (!((l2 < r2 && l1 <= r1) || (l1 <= r2 && r2 <= r1) || (l1 <= l2 && l2 <= r1))) {
						valid = false;
						break;
					}
				}
			}
			if (valid) {
				return true;
			}
		}
	}
	return false;
}

double min_height(int N, const vector<point2d>& P, double R) {
	vector<vector<vector<point2d> > > anglist(N, vector<vector<point2d> >(N, vector<point2d>(N)));
	for (int i = 0; i < N; i++) {
		for (int j = 0; j < N; j++) {
			if (i == j) {
				continue;
			}
			point2d evec = P[j] - P[i];
			double elen = evec.abs();
			for (int k = 0; k < N; k++) {
				double slen = (P[k] - P[i]).abs();
				double theta = (i != k ? acos(max(min(evec.dot(P[k] - P[i]) / (elen * slen), +1.0), -1.0)) : 0.0);
				if ((k - i + N) % N < (j - i + N) % N) {
					theta *= -1.0;
				}
				anglist[i][j][k] = point2d(cos(theta), sin(theta)) * slen;
			}
		}
	}
	double hl = 0.0, hr = 2.0 * R;
	while (hr - hl > 1.0e-7) {
		double h = (hl + hr) * 0.5;
		if (check(N, P, R, R - h, anglist) == true) {
			hr = h;
		}
		else {
			hl = h;
		}
	}
	return hr;
}

int main() {
	while (true) {
		int N;
		cin >> N;
		if (N == 0) {
			break;
		}
		vector<point2d> P1(N);
		for (int i = 0; i < N; i++) {
			cin >> P1[i].x >> P1[i].y;
		}
		int M;
		cin >> M;
		vector<point2d> P2(M);
		for (int i = 0; i < M; i++) {
			cin >> P2[i].x >> P2[i].y;
		}
		double l = 0.0, r = 1.0e+4;
		while (r - l > 1.0e-7) {
			double m = (l + r) * 0.5;
			double res1 = min_height(N, P1, m);
			double res2 = min_height(M, P2, m);
			if (res1 + res2 <= 2 * m) {
				r = m;
			}
			else {
				l = m;
			}
		}
		cout.precision(15);
		cout << r * 2.0 << endl;
	}
	return 0;
}
accuracy: 1
time_ms: 7380
memory_kb: 5228
final_rank: 16

code_snippet: //Let's join Kaede Takagaki Fan Club !!
#pragma GCC optimize("Ofast")
#pragma GCC optimize("unroll-loops")
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <ctime>
#include <cassert>
#include <string>
#include <algorithm>
#include <vector>
#include <queue>
#include <stack>
#include <functional>
#include <iostream>
#include <map>
#include <set>
#include <unordered_map>
#include <unordered_set>
#include <cassert>
#include <iomanip>
#include <chrono>
#include <random>
#include <bitset>
#include <complex>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace std;
#define int long long
//#define L __int128
typedef long long ll;
typedef pair<int,int> P;
typedef pair<int,P> P1;
typedef pair<P,P> P2;
#define pu push
#define pb push_back
#define eb emplace_back
#define mp make_pair
#define eps 1e-7
#define INF 1000000000
#define a first
#define b second
#define fi first
#define sc second
#define rng(i,a,b) for(int i=(int)(a);i<(int)(b);i++)
#define rep(i,x) for(int i=0;i<x;i++)
#define repn(i,x) for(int i=1;i<=x;i++)
#define SORT(x) sort(x.begin(),x.end())
#define ERASE(x) x.erase(unique(x.begin(),x.end()),x.end())
#define POSL(x,v) (lower_bound(x.begin(),x.end(),v)-x.begin())
#define POSU(x,v) (upper_bound(x.begin(),x.end(),v)-x.begin())
#define all(x) x.begin(),x.end()
#define si(x) int(x.size())
 
#ifdef LOCAL
#define dmp(x) cerr<<__LINE__<<" "<<#x<<" "<<x<<endl
#else
#define dmp(x) void(0)
#endif
 
template<class t,class u> bool chmax(t&a,u b){if(a<b){a=b;return true;}else return false;}
template<class t,class u> bool chmin(t&a,u b){if(b<a){a=b;return true;}else return false;}
 
template<class t> using vc=vector<t>;
 
template<class t,class u>
ostream& operator<<(ostream& os,const pair<t,u>& p){
	return os<<"{"<<p.fi<<","<<p.sc<<"}";
}
 
template<class t> ostream& operator<<(ostream& os,const vc<t>& v){
	os<<"{";
	for(auto e:v)os<<e<<",";
	return os<<"}";
}
 
template<class T>
void g(T &a){
	cin >> a;
}
template<class T>
void o(const T &a,bool space=false){
	cout << a << (space?' ':'\n');
}
//ios::sync_with_stdio(false);
//const ll mod = 998244353;
const ll mod = 1000000007;
mt19937_64 mt(chrono::steady_clock::now().time_since_epoch().count());
template<class T>
void add(T&a,T b){
	a+=b;
	if(a >= mod) a-=mod;
}
ll modpow(ll x,ll n){
	ll res=1;
	while(n>0){
		if(n&1) res=res*x%mod;
		x=x*x%mod;
		n>>=1;
	}
	return res;
}
#define _sz 1
ll F[_sz],R[_sz];
void make(){
	F[0] = 1;
	for(int i=1;i<_sz;i++) F[i] = F[i-1]*i%mod;
	R[_sz-1] = modpow(F[_sz-1], mod-2);
	for(int i=_sz-2;i>=0;i--) R[i] = R[i+1] * (i+1) % mod;
}
ll C(int a,int b){
	if(b < 0 || a < b) return 0;
	return F[a]*R[b]%mod*R[a-b]%mod;
}
#define double long double
typedef complex<double> pt;
typedef pair<pt,pt> L;
typedef vector<P> poly;
const double EPS = 1e-15;
#define x real()
#define y imag()
bool eq(double a,double b){
  return (-EPS < a-b && a-b < EPS);
}
double dot(pt a,pt b){
	return (conj(a)*b).x;
}
double cross(pt a,pt b){
	return (conj(a)*b).y;
}
int ccw(pt a,pt b,pt c){
	b -= a; c -= a;
	if(cross(b,c) > EPS) return 1; // counter clockwise
	if(cross(b,c) < -EPS) return -1; // clockwise
	if(dot(b,c) < -EPS) return 2; //c-a-b
	if(norm(b) < norm(c)) return -2; //a-b-c
	return 0; //a-c-b
}
bool cmp(const pt& a,const pt& b){
	if(-EPS < a.x-b.x && a.x-b.x < EPS) return a.y < b.y;
	else return a.x < b.x;
}
vector<pt>convex_hull(vector<pt>ps)
{
	sort(ps.begin(),ps.end(),cmp);
	int k=0,n = ps.size();
	vector<pt>qs(n*2);
	for(int i=0;i<n;i++)
	{
		while(k>1 && ccw(qs[k-2],qs[k-1],ps[i]) == -1) k--;
		qs[k++] = ps[i];
	}
	for(int i=n-2,t=k;i>=0;i--)
	{
		while(k>t && ccw(qs[k-2],qs[k-1],ps[i]) == -1) k--;
		qs[k++] = ps[i];
	}
	qs.resize(k-1);
	return qs;
}
//平行?
bool is_par(pt a,pt b,pt c,pt d){
    b -= a; d -= c;
	if(abs(b.y*d.x - b.x*d.y) < EPS){
		return 1;
	}
	return 0;
}

//直線同士
pt crossPoint(pt a,pt b,pt c,pt d){
	double A = cross(b-a,d-c);
	double B = cross(b-a,b-c);
	if( fabs(A) < EPS && fabs(B) < EPS ) return c;
	else if(fabs(A) >= EPS ) return c+B/A*(d-c);
	else return pt(1e9,1e9);
}
//線分同士の交点
bool on_segment(pair<pt,pt> a,pt p){
  return eq(abs(a.first-a.second)-abs(a.first-p)-abs(a.second-p),0);
}
//円 & 円 の交点
vector<pt> CCintersect (pair<pt,double> c, pair<pt,double> d) {
    vector<pt> ret;
    double dist = abs(c.first - d.first);
    double cr = c.second;
    double dr = d.second;
     
    if (dist > cr + dr) return ret;
    if (dist < abs(cr - dr)) return ret;
     
    double s = (cr + dr + dist) / 2.;
    double area = sqrt(s * (s - cr) * (s - dr) * (s - dist));
    double h = 2 * area / dist;
     
    pt v = d.first - c.first; v /= abs(v);
    pt m = c.first + sqrt(cr * cr - h * h) * v;
    pt n = v * pt(0, 1);
     
    ret.push_back(m + n * h);
    ret.push_back(m - n * h);
    return ret;
}
//線分a-b とc の距離
double dist_lp(pt a,pt b,pt c){
	if(dot(a-b,c-b) <= 0.0) return abs(c-b);
	if(dot(b-a,c-a) <= 0.0) return abs(c-a);
	return abs(cross(b-a,c-a)) / abs(b-a);
}
//線分が交わる?
bool intersect(pt a,pt b,pt c,pt d){
	return (ccw(a,b,c)*ccw(a,b,d) <= 0 && ccw(c,d,a)*ccw(c,d,b) <= 0);
}
//線分a-b と 線分c-d の距離
double min_dist_ll(pt a,pt b,pt c,pt d){
    if(intersect(a,b,c,d) == true) return 0.0;
    double ret = 1e18;
    ret = min(ret,dist_lp(a,b,c));
    ret = min(ret,dist_lp(a,b,d));
    ret = min(ret,dist_lp(c,d,a));
    ret = min(ret,dist_lp(c,d,b));
    return ret;
}
bool contain_point(vector<pt>ps,pt p){
	double sum = 0;
	//arg no sum wo keisan
	for(int i=0;i<ps.size();i++){
		if(on_segment(mp(ps[i],ps[ (i+1)%ps.size() ]),p)) return 1;
		sum += arg( (ps[ (i+1)%ps.size() ]-p) / (ps[i]-p) );
	}
	return (abs(sum) > 1);
}
bool LCMP(const pt& a,const pt& b){
	if(eq(a.x,b.x)) return a.y < b.y;
	else return a.x < b.x;
}
bool contain_segment(vector<pt>ps,pt p,pt q){
        vector<pt> qs;
        qs.pb(p); qs.pb(q);
    	for(int i=0;i<ps.size();i++){
    		//on-segment
    		if(ccw(p,q,ps[i]) == 0) qs.pb(ps[i]);
    	}
        for(int i=0;i<ps.size();i++){
        	pt r = crossPoint(p,q,ps[i],ps[(i+1)%ps.size()]);
        	if(r.x > 1e8) continue;
        	if(ccw(p,q,r) == 0) qs.pb(r);
        }
        sort(qs.begin(),qs.end(),LCMP);
        for(int i=1;i<qs.size();i++){
            pt r = (qs[i] + qs[i-1]) / (double)2.0;
            if(!contain_point(ps, r)) return 0;
        }
        return 1;
}
//G -> counter-clockwise
vector<pt> convex_cut(vector<pt> G, pair<pt,pt>l){
  vector<pt> ans;
  for(int i=0;i<(int)G.size();i++){
    pt A = G[i];
    pt B = G[(i+1)%G.size()];
    if(ccw(l.fi,l.sc,A) != -1) ans.pb(A);
    if(ccw(l.fi,l.sc,A) * ccw(l.fi,l.sc,B) < 0)
      ans.pb(crossPoint(A,B,l.fi,l.sc));
  }
  return ans;
}
vector<pair<pt,pt> >LL;
void add(pt c1,double r1,pt c2,double r2){
	//2-circle tangent line
	c2-=c1; // later add c1
	//(0,0) and c2
	//uchigawa
	double IN = norm(c2)-(r1+r2)*(r1+r2);
	if(IN >= 0){
        double c3_x_1 = r1 / norm(c2) * (c2.x * (r1+r2) + c2.y * sqrt(norm(c2)-(r1+r2)*(r1+r2)) );
        double c3_y_1 = r1 / norm(c2) * (c2.y * (r1+r2) - c2.x * sqrt(norm(c2)-(r1+r2)*(r1+r2)) );
        double c3_x_2 = r1 / norm(c2) * (c2.x * (r1+r2) - c2.y * sqrt(norm(c2)-(r1+r2)*(r1+r2)) );
        double c3_y_2 = r1 / norm(c2) * (c2.y * (r1+r2) + c2.x * sqrt(norm(c2)-(r1+r2)*(r1+r2)) );
        pt T2 = pt(c3_x_1,c3_y_1); T2 *= pt(0.0,1.0); LL.pb(mp(pt(c3_x_1,c3_y_1)+c1,pt(c3_x_1,c3_y_1)+c1+T2));
        T2 = pt(c3_x_2,c3_y_2); T2 *= pt(0.0,1.0); LL.pb(mp(pt(c3_x_2,c3_y_2)+c1,pt(c3_x_2,c3_y_2)+c1+T2));
    }
    //sotogawa
    IN = norm(c2)-(r1-r2)*(r1-r2);
    if(IN >= 0){
        double c3_x_1 = r1 / norm(c2) * (c2.x * (r1-r2) + c2.y * sqrt(norm(c2)-(r1-r2)*(r1-r2)) );
        double c3_y_1 = r1 / norm(c2) * (c2.y * (r1-r2) - c2.x * sqrt(norm(c2)-(r1-r2)*(r1-r2)) );
        double c3_x_2 = r1 / norm(c2) * (c2.x * (r1-r2) - c2.y * sqrt(norm(c2)-(r1-r2)*(r1-r2)) );
        double c3_y_2 = r1 / norm(c2) * (c2.y * (r1-r2) + c2.x * sqrt(norm(c2)-(r1-r2)*(r1-r2)) );
        pt T2 = pt(c3_x_1,c3_y_1); T2 *= pt(0.0,1.0); LL.pb(mp(pt(c3_x_1,c3_y_1)+c1,pt(c3_x_1,c3_y_1)+c1+T2));
        T2 = pt(c3_x_2,c3_y_2); T2 *= pt(0.0,1.0); LL.pb(mp(pt(c3_x_2,c3_y_2)+c1,pt(c3_x_2,c3_y_2)+c1+T2));
    }
}
pt project(pt po,pair<pt,pt> L){
	pt base = L.sc-L.fi;
	double r = dot(po-L.fi,base) / norm(base);
	return L.fi+base*r;
}
pt reflect(pt po,pair<pt,pt> L){
	return po + (project(po,L)-po)*(double)2.;
}
void mergee(vector<pair<pt,pt> > &segments) {
    for(int i = 0; i < segments.size(); ) {
        const pair<pt,pt> &s1 = segments[i];
        bool ok = true;
        for(int j = i + 1; j < segments.size(); ++j) {
            const pair<pt,pt> &s2 = segments[j];
 
            if(intersect(s1.fi,s1.sc,s2.fi,s2.sc) && abs(cross(s1.fi-s1.sc,s2.fi-s2.sc)) <= EPS) {
                pt a = pt(1e9,1e9),b = pt(-1e9,-1e9);
                if(a.x > s1.fi.x) a=s1.fi; else if(abs(a.x-s1.fi.x)<=EPS && a.y > s1.fi.y) a = s1.fi;
                if(a.x > s1.sc.x) a=s1.sc; else if(abs(a.x-s1.sc.x)<=EPS && a.y > s1.sc.y) a = s1.sc;
                if(a.x > s2.fi.x) a=s2.fi; else if(abs(a.x-s2.fi.x)<=EPS && a.y > s2.fi.y) a = s2.fi;
                if(a.x > s2.sc.x) a=s2.sc; else if(abs(a.x-s2.sc.x)<=EPS && a.y > s2.sc.y) a = s2.sc;
                if(b.x < s1.fi.x) b=s1.fi; else if(abs(b.x-s1.fi.x)<=EPS && b.y < s1.fi.y) b = s1.fi;
                if(b.x < s1.sc.x) b=s1.sc; else if(abs(b.x-s1.sc.x)<=EPS && b.y < s1.sc.y) b = s1.sc;
                if(b.x < s2.fi.x) b=s2.fi; else if(abs(b.x-s2.fi.x)<=EPS && b.y < s2.fi.y) b = s2.fi;
                if(b.x < s2.sc.x) b=s2.sc; else if(abs(b.x-s2.sc.x)<=EPS && b.y < s2.sc.y) b = s2.sc;
                segments.push_back(mp(a, b));
                segments.erase(segments.begin() + j);
                segments.erase(segments.begin() + i);
                ok = false;
                break;
            }
        }
        if(ok) ++i;
    }
}
bool CMPP(const pair<int,double>&a,const pair<int,double>&b){
	return a.sc < b.sc;
}
bool cmpp(const pt&a,const pt&b){
	if(abs(a.x-b.x)>EPS) return a.x < b.x;
	else return a.y<b.y;
}
void arrangement(vector<pair<pt,pt> > &segments, vector<pt> &points) {
    mergee(segments);
    const int n = segments.size();
    points.clear();
 
    for(int i = 0; i < n; ++i) {
        const pair<pt,pt> &s1 = segments[i];
        points.pb(s1.fi);
        points.pb(s1.sc);
 
        for(int j = i + 1; j < n; ++j) {
            const pair<pt,pt> &s2 = segments[j];
            if(intersect(s1.fi,s1.sc,s2.fi,s2.sc)) points.pb(crossPoint(s1.fi,s1.sc,s2.fi,s2.sc));
        }
    }
 
    sort(points.begin(),points.end(),cmpp);
    points.erase(unique(points.begin(),points.end()), points.end());
 
    const int V = points.size();
    vector<pair<int,double> >G[V];
    for(const pair<pt,pt> &s : segments) {
        vector<pair<double, int>> vs;
        for(int i = 0; i < V; ++i) {
            if(ccw(s.fi,s.sc,points[i]) == 0) vs.pb(mp(norm(s.fi - points[i]), i));
        }
 
        sort(vs.begin(),vs.end());
        for(int i = 1; i < vs.size(); ++i) {
            const int v = vs[i].second;
            const int u = vs[i - 1].second;
            G[v].pb(mp(u, arg(points[u] - points[v])));
            G[u].pb(mp(v, arg(points[v] - points[u])));
        }
    }
    for(int i=0;i<V;i++){
    	sort(G[i].begin(),G[i].end(),CMPP);
    }
    //return G;
}
//面積
double area(vc<pt>ax){
    int n = ax.size();
	/*
	//only for convex polygons!!
	//convert to counter-clockwise
	for(int i=0;i<n;i++){
    	int f = ccw(ax[(i+0)%n], ax[(i+1)%n], ax[(i+2)%n]);
    	if(abs(f) == 1); else continue;
    	
    	if(f != 1){
    		for(int i=1;i<n;i++){
    			if(i >= n-i) break;
    			swap(ax[i], ax[n-i]);
    		}
    	}
    	break;
	}
	*/
	double ans = 0.0;
	for(int i=0;i<n;i++){
		ans += cross(ax[i], ax[(i+1)%n]);
	}
	return abs(ans) / 2.0;
}
double pi = acos(-1.0L);
pair<pt, pt>cross_CL(pair<pt, double>c, pair<pt, pt>l){
	pt mid = project(c.a, l);
	if(abs(mid - c.a) < eps){
		//cross center
		double d = arg(l.b - l.a);
		auto vec = polar(c.b, d);
		return mp(c.a + vec, c.a - vec);
	}
	if(abs(mid - c.a) > c.b+eps){
		//not intersect
		return mp(pt(1e18, 1e18), pt(1e18, 1e18));
	}
	if(abs(mid - c.a) > c.b-eps){
		//tangent
		return mp(mid, mid);
	}
	double len = sqrt(c.b*c.b - abs(mid - c.a)*abs(mid - c.a));
	auto vec = mid - c.a;
	vec = vec / abs(vec) * len * polar(1.0L, pi/2);
	return mp(mid + vec, mid - vec);
}
//複数テストケースなので積み上げる変数はローカルに！
//置けないなら必ず初期化！
int n, m;
void solve(){
	//最初の入力は済んでいる
	vc<pt>a[2];
	rep(i, n){
		double ax, ay; cin >> ax >> ay;
		a[0].pb(pt(ax, ay));
	}
	cin>>m;
	rep(i, m){
		double ax, ay; cin >> ax >> ay;
		a[1].pb(pt(ax, ay));
	}
	//calculate minimum length of arc of circle radius = r
	//s.t. contain all points of p
	auto calc = [&](vc<pt>p, double r) -> double{
		vc<pt>cand;
		int n = p.size();
		rep(i, n) rep(j, i){
			if(abs(p[i] - p[j]) > r * 2.0-eps) continue;
			auto mid = (p[i] + p[j]) / 2.0L;
			double len = sqrt(r*r - abs(p[i]-p[j]) * abs(p[i]-p[j]) / 4.0L);
			auto vec = p[i]-p[j];
			vec = vec / abs(vec) * len * polar(1.0L, pi/2);
			cand.pb(mid + vec);
			cand.pb(mid - vec);
		}
		rep(i, n) rep(j, n){
			auto vec = p[j] - p[(j+1)%n];
			vec = vec / abs(vec) * r * polar(1.0L, pi/2);
			cand.pb(p[i] + vec);
			cand.pb(p[i] - vec);
		}
		double ret = 1e18;
		for(auto c:cand){
			bool bad = 0;
			rep(i, n){
				if(abs(c-p[i]) > r + eps) {
					bad = 1;
					goto fail;
				}
			}
			fail:;
			if(bad) continue;
			rep(i, n){
				auto cs = cross_CL(mp(c, r), mp(p[i], p[(i+1)%n]));
				auto p1 = c + polar(r, arg(cs.a-cs.b)+pi/2.0L);
				auto p2 = c - polar(r, arg(cs.a-cs.b)+pi/2.0L);
				if(ccw(p[i], p[(i+1)%n], p1) == 1);
				else{
					assert(ccw(p[i], p[(i+1)%n], p2) == 1);
					swap(p1, p2);
				}
				if(ccw(cs.a, cs.b, p1) != 1){
					assert(ccw(cs.b, cs.a, p1) == 1);
					swap(cs.a, cs.b);
				}
				double p = arg((p1-c) / (cs.b-c));
				double q = arg((cs.a-c) / (p1-c));
				assert(p >= 0 and q >= 0 and abs(p-q) <= eps);
				chmin(ret, r * (p + q));
			}
			rep(i, n){
				if(abs(c - p[i]) <= eps){
					chmin(ret, r * pi);
				}
				else{
					auto v = (c-p[i]) * polar(1.0L, pi/2);
					auto cs = cross_CL(mp(c, r), mp(p[i]-v, p[i]+v));
					if(abs(cs.a-cs.b) < eps){
						chmin(ret, r * pi * 2);
						continue;
					}
					bool w[2] = {}, bad = 0;
					rep(j, n){
						if(i == j) continue;
						int f = ccw(cs.a, cs.b, p[j]);
						if(abs(f) != 1) {
							bad = 1;
							break;
						}
						w[f<0] = 1;
					}
					if(w[0] and w[1]) continue;
					if(bad) continue;
					
					if(w[1]) swap(cs.a, cs.b);
					auto p1 = c + polar(r, arg(cs.a-cs.b)+pi/2.0L);
					auto p2 = c - polar(r, arg(cs.a-cs.b)+pi/2.0L);
					
					if(ccw(cs.a, cs.b, p1) != 1){
						assert(ccw(cs.a, cs.b, p2) == 1);
						swap(p1, p2);
					}
					double p = arg((p1-c) / (cs.b-c));
					double q = arg((cs.a-c) / (p1-c));
					assert(p >= 0 and q >= 0 and abs(p-q) <= eps);
					chmin(ret, r * (p + q));
				}
			}
		}
		return ret;
	};
	double lb = 0.0, ub = 2500.0;
	rep(_, 100){
		double mid = (lb + ub) / 2;
		double flag = 0.0;
		flag += calc(a[0], mid);
		flag += calc(a[1], mid);
		
		if(flag <= mid * pi * 2.0L) ub = mid;
		else lb = mid;
	}
	o(ub * 2.0L);
}
signed main(){
	//cin.tie(0);
	ios::sync_with_stdio(0);
	cout<<fixed<<setprecision(20);
	while(true){
		cin>>n;
		//終了条件
		if(n==0) return 0;
		solve();
	}
}
accuracy: 1
time_ms: 4460
memory_kb: 3968
final_rank: 8

code_snippet: #include<bits/stdc++.h>
using namespace std;
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



#define SIZE 50

enum Type{
	A,
	B,
};

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;

struct Line{
	Line(){

	}
	Line(Point a,Point b){
		p[0] = a;
		p[1] = b;
	}
	void outPut(){

		printf("(%.3lf,%.3lf)-(%.3lf,%.3lf)\n",p[0].x,p[0].y,p[1].x,p[1].y);
	}
	Point p[2];
};

struct Circle{
	Point center;
	double r;
};

int N[2];
double NUM = 50000;
Line LINE[2][SIZE];
vector<Line> vert_line[2][SIZE];
Polygon input[2];
Point point[2][SIZE][SIZE][SIZE];


double calc_dist(Point A,Point B){

	return sqrt((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y));
}

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;
}


double calc_slope(Line A){

	if(fabs(A.p[0].x-A.p[1].x) < EPS){

		return DBL_MAX;

	}else if(fabs(A.p[0].y-A.p[1].y) < EPS){

		return 0;

	}else{

		return (A.p[1].y-A.p[0].y)/(A.p[1].x-A.p[0].x);
	}
}


Point project(Line l,Point p){

	Vector base = l.p[1]-l.p[0];
	double r = dot(p-l.p[0],base)/norm(base);
	return l.p[0]+base*r;
}

//円と直線の交点を求める関数
vector<Point> getCrossPoints(Circle c,Line l){

	vector<Point> ret;

	Vector pr = project(l,c.center);
	Vector e = (l.p[1]-l.p[0])/abs(l.p[1]-l.p[0]);

	double base;

	if(fabs(c.r*c.r-norm(pr-c.center)) < EPS){

		base = 0;
	}else{
		base = sqrt(c.r*c.r-norm(pr-c.center));
	}

	ret.push_back(Point(pr+e*base));
	ret.push_back(Point(pr-e*base));

	return ret;
}

int func(double x1,double y1,double x2, double y2, double xp, double yp){
	double naiseki,norm1,norm2,gaiseki;
	norm1 = sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
	norm2 = sqrt((xp-x1)*(xp-x1)+(yp-y1)*(yp-y1));
	naiseki = (xp-x1)*(x2-x1)+(yp-y1)*(y2-y1);
	gaiseki = (x2-x1)*(yp-y1)-(xp-x1)*(y2-y1);
	if(gaiseki > EPS){
		return 1;
	}else if(gaiseki < -EPS){
		return -1;
	}
	if(naiseki < -EPS){
		return 2;
	}

	if(norm1 < norm2){
		return -2;
	}
	return 0;
}


//★★直線ではなく、線分の交差判定★★
bool is_Cross(Line a,Line b){

	if(func(a.p[0].x,a.p[0].y,a.p[1].x,a.p[1].y,b.p[0].x,b.p[0].y)*
			func(a.p[0].x,a.p[0].y,a.p[1].x,a.p[1].y,b.p[1].x,b.p[1].y) <= 0 &&
			func(b.p[0].x,b.p[0].y,b.p[1].x,b.p[1].y,a.p[0].x,a.p[0].y)*
			func(b.p[0].x,b.p[0].y,b.p[1].x,b.p[1].y,a.p[1].x,a.p[1].y) <= 0){
		return true;
	}
	return false;
}



Point calc_minus(Point a,Point b){
    Point ret;

    ret.x = a.x-b.x;
    ret.y = a.y-b.y;

    return ret;
}

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

//線分ではなく直線と点の距離
double getDistanceLP(Line l,Point p){
    return fabs(cross(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0]))/calc_len(calc_minus(l.p[1],l.p[0])));
}

//点と線分の距離
double getDistanceSP(Line l,Point p){
	if(dot(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0])) < 0.0)return calc_len(calc_minus(p,l.p[0]));
	if(dot(calc_minus(l.p[0],l.p[1]),calc_minus(p,l.p[1])) < 0.0)return calc_len(calc_minus(p,l.p[1]));
	return getDistanceLP(l,p);
}

//線分と線分の距離
double getDistance(Line A,Line B){
	if(is_Cross(A,B))return 0.0;
	return min(min(getDistanceSP(A,B.p[0]),getDistanceSP(A,B.p[1])),
			min(getDistanceSP(B,A.p[0]),getDistanceSP(B,A.p[1])));
}


//交点を求める関数
Point calc_Cross_Point(double x1,double x2,double x3,double x4,double y1,double y2,double y3,double y4){
	Point ret;
	ret.x = ((x2-x1)*(y3*(x4-x3)+x3*(y3-y4))-(x4-x3)*(y1*(x2-x1)+x1*(y1-y2)))/((y2-y1)*(x4-x3)-(y4-y3)*(x2-x1));
	if(fabs(x1-x2) > EPS){
		ret.y = ((y2-y1)*ret.x+y1*(x2-x1)+x1*(y1-y2))/(x2-x1);
	}else{
		ret.y = ((y4-y3)*ret.x+y3*(x4-x3)+x3*(y3-y4))/(x4-x3);
	}
	return ret;
}

//インタフェース関数
Point calc_Cross_Point(Point a,Point b,Point c,Point d){
	return calc_Cross_Point(a.x,b.x,c.x,d.x,a.y,b.y,c.y,d.y);
}

Point calc_Cross_Point(Line A,Line B){

	if(getDistanceSP(B,A.p[0]) < EPS){

		return A.p[0];

	}else if(getDistanceSP(B,A.p[1]) < EPS){

		return A.p[1];

	}else if(getDistanceSP(A,B.p[0]) < EPS){

		return B.p[0];

	}else if(getDistanceSP(A,B.p[1]) < EPS){

		return B.p[1];
	}

	return calc_Cross_Point(A.p[0],A.p[1],B.p[0],B.p[1]);
}


/*
 * IN 2
 * ON 1
 * OUT 0
 *
 */
int contains(Polygon g,Point p){
	int n = g.size();
	bool x = false;
	for(int i = 0; i < n; i++){
		Point a = g[i]-p,b = g[(i+1)%n]-p;
		if(abs(cross(a,b)) < EPS && dot(a,b) < EPS)return 1;
		if(a.y > b.y)swap(a,b);
		if(a.y < EPS && EPS < b.y && cross(a,b) > EPS) x = !x;
	}
	return (x ? 2:0);
}



//点の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;
			}
		}
	}
}

/*点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;
}


bool isOK(double R){

	double MINI[2] = {BIG_NUM,BIG_NUM};

	for(int loop = 0; loop < 2; loop++){

		for(int base = 0; base < N[loop]; base++){ //50*40*2 = 4000

			Circle C;
			C.center = input[loop][base];
			C.r = R;

			//円の中心候補
			vector<Point> vec;

			for(int i = 0; i < vert_line[loop][base].size(); i++){

				if(getDistanceSP(vert_line[loop][base][i],C.center) +EPS < R){
					vector<Point> work = getCrossPoints(C,vert_line[loop][base][i]);
					for(int c = 0; c < work.size(); c++){

						vec.push_back(work[c]);
					}
				}
			}

			if(vec.size() == 0)continue;

			sort(vec.begin(),vec.end());
			vec.erase(unique(vec.begin(),vec.end()),vec.end());


			for(int k = 0; k < vec.size(); k++){

				//自分自身が円に収まっているか
				bool FLG = true;
				for(int a = 0; a < N[loop]; a++){ //4000*40 = 16万

					double tmp_dist = calc_dist(vec[k],input[loop][a]);
					if(tmp_dist > R+EPS){

						FLG = false;
						break;
					}
				}
				if(!FLG){
					continue;
				}

				bool is_IN = contains(input[loop],vec[k]);

				//ポリゴンの辺への最短距離を求める
				double mini = R,max_h;
				int ind = -1;

				for(int a = 0; a < N[loop]; a++){

					double tmp_dist = getDistanceSP(LINE[loop][a],vec[k]);
					if(mini > tmp_dist+EPS){

						mini = tmp_dist;
						ind = a;
					}
				}

				if(is_IN){ //円の中心が多角形の内部にある

					max_h = R-mini; //円の断片の最大高さ


				}else{ //円の中心が多角形の外部にある

					max_h = R+mini; //円の断片の最大高さ
				}

				MINI[loop] = min(MINI[loop],2*R-max_h);	//ポリゴンを収めるのに必要な、円の断片の最小の高さ

				//baseを中心に図形を回転させる
				double LEFT = -M_PI,RIGHT = M_PI;
				double mid[3];

				for(int J = 0; J < 45; J++){

					mid[1] = (2.0*LEFT+RIGHT)/3.0;
					mid[2] = (1.0*LEFT+2.0*RIGHT)/3.0;

					double dist1 = 2*R,dist2 = 2*R;

					for(int c = 0; c < 2; c++){

						Polygon tmp_poly;
						bool all_IN = true;
						for(int d = 0; d < N[loop]; d++){ //4000*50*40 = 800万

							Point tmp_p = rotate(input[loop][base],input[loop][d],mid[c+1]);
							double work_dist = calc_dist(vec[k],tmp_p);
							if(work_dist > R+EPS){

								all_IN = false;
								break;
							}
							tmp_poly.push_back(tmp_p);
						}

						if(!all_IN){

							continue;
						}

						mini = R;

						//回転させた図形と、円の中心との距離を見る
						for(int a = 0; a < N[loop]; a++){

							Line calc_line = Line(tmp_poly[a],tmp_poly[(a+1)%N[loop]]);
							double work_dist = getDistanceSP(calc_line,vec[k]);

							if(mini > work_dist+EPS){

								mini = work_dist;
								ind = a;
							}
						}

						double tmp_h,tmp_d;

						if(contains(tmp_poly,vec[k])){

							tmp_h = R-mini; //円の断片の最大高さ
							tmp_d = 2*R-tmp_h;

						}else{

							tmp_h = R+mini; //円の断片の最大高さ
							tmp_d = 2*R-tmp_h;
						}

						if(c == 0){

							dist1 = tmp_d;
						}else{

							dist2 = tmp_d;
						}
					}

					if(fabs(dist1-2*R) < EPS && fabs(dist2-2*R) < EPS){

						LEFT = mid[1];
						RIGHT = mid[2];
						continue;
					}

					MINI[loop] = min(MINI[loop],min(dist1,dist2));

					if(dist1 < dist2){

						RIGHT = mid[2];
					}else{

						LEFT = mid[1];
					}
				}
			}
		}
	}

	return MINI[A]+MINI[B] <= 2*R+EPS; //円の断片の高さの和が直径以下ならOK(凸多角形なので、ある直線より上に全ての点を配置させることができる)
}


void func(){

	input[A].clear();
	input[B].clear();

	for(int i = 0; i < 2; i++){
		for(int k = 0; k < SIZE; k++){

			vert_line[i][k].clear();
		}
	}

	double x,y;

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

		scanf("%lf %lf",&x,&y);
		input[A].push_back(Point(x,y));
	}

	scanf("%d",&N[B]);

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

		scanf("%lf %lf",&x,&y);
		input[B].push_back(Point(x,y));
	}

	double maxi = 0;

	for(int loop = 0; loop < 2; loop++){
		for(int i = 0; i < N[loop]-1; i++){
			for(int k = i+1; k < N[loop]; k++){

				double tmp_dist = calc_dist(input[loop][i],input[loop][k]);
				maxi = max(maxi,tmp_dist);
			}
		}
	}

	for(int loop = 0; loop < 2; loop++){
		for(int i = 0; i < N[loop]; i++){

			Point a = input[loop][i];
			Point b = input[loop][(i+1)%N[loop]];

			LINE[loop][i] = Line(a,b);
		}
	}

	//各基準点ごとに垂直二等分線を求める
	for(int loop = 0; loop < 2; loop++){
		for(int base = 0; base < N[loop]; base++){
			for(int adj = 0; adj < N[loop]; adj++){
				if(adj == base)continue;

				Point p = input[loop][base];
				Point q = input[loop][adj];

				Point mid_p = (p+q)/2;

				Line tmp_line;

				if(fabs(p.x-q.x) < EPS){ //垂直

					//垂直二等分線
					tmp_line.p[0] = Point(mid_p.x-NUM,mid_p.y);
					tmp_line.p[1] = Point(mid_p.x+NUM,mid_p.y);

				}else if(fabs(p.y-q.y) < EPS){ //水平

					tmp_line.p[0] = Point(mid_p.x,mid_p.y+NUM);
					tmp_line.p[1] = Point(mid_p.x,mid_p.y-NUM);

				}else{

					double tmp_slope = calc_slope(Line(p,q));

					if(p.x > q.x){

						swap(p,q);
					}

					double vert_slope = -1.0/tmp_slope;

					tmp_line.p[0] = Point(mid_p.x-NUM,mid_p.y-NUM*vert_slope);
					tmp_line.p[1] = Point(mid_p.x+NUM,mid_p.y+NUM*vert_slope);
				}

				vert_line[loop][base].push_back(tmp_line);
			}
		}
	}


	//半径を二分探索
	double left = maxi/2,right = 2001,mid = (left+right)/2;
	double ans = 2001;
	double pre = BIG_NUM;

	for(int loop = 0; loop < 50; loop++){

		if(fabs(pre-mid) < 1e-8)break;
		pre = mid;

		if(isOK(mid)){

			ans = mid;
			right = mid;
		}else{

			left = mid;
		}
		mid = (left+right)/2;
	}

	printf("%.10lf\n",ans*2);
}


int main(){

	while(true){

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

		func();
	}

	return 0;
}
accuracy: 1
time_ms: 7640
memory_kb: 7656
final_rank: 19

code_snippet: #include<bits/stdc++.h>
using namespace std;
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



#define SIZE 50

enum Type{
	A,
	B,
};

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;

struct Line{
	Line(){

	}
	Line(Point a,Point b){
		p[0] = a;
		p[1] = b;
	}
	void outPut(){

		printf("(%.3lf,%.3lf)-(%.3lf,%.3lf)\n",p[0].x,p[0].y,p[1].x,p[1].y);
	}
	Point p[2];
};

struct Circle{
	Point center;
	double r;
};

int N[2];
double NUM = 50000;
Line LINE[2][SIZE];
vector<Line> vert_line[2][SIZE];
Polygon input[2];
Point point[2][SIZE][SIZE][SIZE];


double calc_dist(Point A,Point B){

	return sqrt((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y));
}

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;
}


double calc_slope(Line A){

	if(fabs(A.p[0].x-A.p[1].x) < EPS){

		return DBL_MAX;

	}else if(fabs(A.p[0].y-A.p[1].y) < EPS){

		return 0;

	}else{

		return (A.p[1].y-A.p[0].y)/(A.p[1].x-A.p[0].x);
	}
}


Point project(Line l,Point p){

	Vector base = l.p[1]-l.p[0];
	double r = dot(p-l.p[0],base)/norm(base);
	return l.p[0]+base*r;
}

//円と直線の交点を求める関数
vector<Point> getCrossPoints(Circle c,Line l){

	vector<Point> ret;

	Vector pr = project(l,c.center);
	Vector e = (l.p[1]-l.p[0])/abs(l.p[1]-l.p[0]);

	double base;

	if(fabs(c.r*c.r-norm(pr-c.center)) < EPS){

		base = 0;
	}else{
		base = sqrt(c.r*c.r-norm(pr-c.center));
	}

	ret.push_back(Point(pr+e*base));
	ret.push_back(Point(pr-e*base));

	return ret;
}

int func(double x1,double y1,double x2, double y2, double xp, double yp){
	double naiseki,norm1,norm2,gaiseki;
	norm1 = sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1));
	norm2 = sqrt((xp-x1)*(xp-x1)+(yp-y1)*(yp-y1));
	naiseki = (xp-x1)*(x2-x1)+(yp-y1)*(y2-y1);
	gaiseki = (x2-x1)*(yp-y1)-(xp-x1)*(y2-y1);
	if(gaiseki > EPS){
		return 1;
	}else if(gaiseki < -EPS){
		return -1;
	}
	if(naiseki < -EPS){
		return 2;
	}

	if(norm1 < norm2){
		return -2;
	}
	return 0;
}


//★★直線ではなく、線分の交差判定★★
bool is_Cross(Line a,Line b){

	if(func(a.p[0].x,a.p[0].y,a.p[1].x,a.p[1].y,b.p[0].x,b.p[0].y)*
			func(a.p[0].x,a.p[0].y,a.p[1].x,a.p[1].y,b.p[1].x,b.p[1].y) <= 0 &&
			func(b.p[0].x,b.p[0].y,b.p[1].x,b.p[1].y,a.p[0].x,a.p[0].y)*
			func(b.p[0].x,b.p[0].y,b.p[1].x,b.p[1].y,a.p[1].x,a.p[1].y) <= 0){
		return true;
	}
	return false;
}



Point calc_minus(Point a,Point b){
    Point ret;

    ret.x = a.x-b.x;
    ret.y = a.y-b.y;

    return ret;
}

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

//線分ではなく直線と点の距離
double getDistanceLP(Line l,Point p){
    return fabs(cross(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0]))/calc_len(calc_minus(l.p[1],l.p[0])));
}

//点と線分の距離
double getDistanceSP(Line l,Point p){
	if(dot(calc_minus(l.p[1],l.p[0]),calc_minus(p,l.p[0])) < 0.0)return calc_len(calc_minus(p,l.p[0]));
	if(dot(calc_minus(l.p[0],l.p[1]),calc_minus(p,l.p[1])) < 0.0)return calc_len(calc_minus(p,l.p[1]));
	return getDistanceLP(l,p);
}

//線分と線分の距離
double getDistance(Line A,Line B){
	if(is_Cross(A,B))return 0.0;
	return min(min(getDistanceSP(A,B.p[0]),getDistanceSP(A,B.p[1])),
			min(getDistanceSP(B,A.p[0]),getDistanceSP(B,A.p[1])));
}


//交点を求める関数
Point calc_Cross_Point(double x1,double x2,double x3,double x4,double y1,double y2,double y3,double y4){
	Point ret;
	ret.x = ((x2-x1)*(y3*(x4-x3)+x3*(y3-y4))-(x4-x3)*(y1*(x2-x1)+x1*(y1-y2)))/((y2-y1)*(x4-x3)-(y4-y3)*(x2-x1));
	if(fabs(x1-x2) > EPS){
		ret.y = ((y2-y1)*ret.x+y1*(x2-x1)+x1*(y1-y2))/(x2-x1);
	}else{
		ret.y = ((y4-y3)*ret.x+y3*(x4-x3)+x3*(y3-y4))/(x4-x3);
	}
	return ret;
}

//インタフェース関数
Point calc_Cross_Point(Point a,Point b,Point c,Point d){
	return calc_Cross_Point(a.x,b.x,c.x,d.x,a.y,b.y,c.y,d.y);
}

Point calc_Cross_Point(Line A,Line B){

	if(getDistanceSP(B,A.p[0]) < EPS){

		return A.p[0];

	}else if(getDistanceSP(B,A.p[1]) < EPS){

		return A.p[1];

	}else if(getDistanceSP(A,B.p[0]) < EPS){

		return B.p[0];

	}else if(getDistanceSP(A,B.p[1]) < EPS){

		return B.p[1];
	}

	return calc_Cross_Point(A.p[0],A.p[1],B.p[0],B.p[1]);
}


/*
 * IN 2
 * ON 1
 * OUT 0
 *
 */
int contains(Polygon g,Point p){
	int n = g.size();
	bool x = false;
	for(int i = 0; i < n; i++){
		Point a = g[i]-p,b = g[(i+1)%n]-p;
		if(abs(cross(a,b)) < EPS && dot(a,b) < EPS)return 1;
		if(a.y > b.y)swap(a,b);
		if(a.y < EPS && EPS < b.y && cross(a,b) > EPS) x = !x;
	}
	return (x ? 2:0);
}



//点の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;
			}
		}
	}
}

/*点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;
}



bool DEBUG = false;

bool isOK(double R){

	double MINI[2] = {BIG_NUM,BIG_NUM};

	if(DEBUG){
		printf("\nR:%.6lf 直径:%.6lf\n",R,2*R);
	}

	for(int loop = 0; loop < 2; loop++){

		if(DEBUG){

			printf("\n\n■■図形:%d■■\n",loop);
		}

		for(int base = 0; base < N[loop]; base++){ //50*40*2 = 4000

			Circle C;
			C.center = input[loop][base];
			C.r = R;

			//円の中心候補
			vector<Point> vec;

			for(int i = 0; i < vert_line[loop][base].size(); i++){

				if(getDistanceSP(vert_line[loop][base][i],C.center) +EPS < R){
					vector<Point> work = getCrossPoints(C,vert_line[loop][base][i]);
					for(int c = 0; c < work.size(); c++){

						vec.push_back(work[c]);
					}
				}
			}

			if(vec.size() == 0)continue;

			sort(vec.begin(),vec.end());
			vec.erase(unique(vec.begin(),vec.end()),vec.end());


			for(int k = 0; k < vec.size(); k++){

				//自分自身が円に収まっているか
				bool FLG = true;
				for(int a = 0; a < N[loop]; a++){ //4000*40 = 16万

					double tmp_dist = calc_dist(vec[k],input[loop][a]);
					if(tmp_dist > R+EPS){

						FLG = false;
						break;
					}
				}
				if(!FLG){
					//printf("収まってない\n");
					continue;
				}

				if(DEBUG){
					printf("\n中心候補:");
					vec[k].debug();
					printf("基準点:");
					input[loop][base].debug();
					for(int i = 0; i < N[loop]; i++){
						printf("点");
						input[loop][i].debug();
						printf("中心との距離:%6lf\n",calc_dist(vec[k],input[loop][i]));
					}
				}

				bool is_IN = contains(input[loop],vec[k]);

				//ポリゴンの辺への最短距離を求める
				double mini = R,max_h;
				int ind = -1;

				for(int a = 0; a < N[loop]; a++){

					double tmp_dist = getDistanceSP(LINE[loop][a],vec[k]);

					/*if(DEBUG){
						printf("線分\n");
						LINE[loop][a].outPut();
						printf("tmp_dist:%.3lf\n",tmp_dist);
					}*/
					if(mini > tmp_dist+EPS){

						mini = tmp_dist;
						ind = a;
					}
				}

				if(is_IN){ //円の中心が多角形の内部にある

					if(DEBUG){

						printf("多角形の中\n");
					}

					max_h = R-mini; //円の断片の最大高さ


				}else{ //円の中心が多角形の外部にある

					if(DEBUG){

						printf("多角形の外\n");
					}

					max_h = R+mini; //円の断片の最大高さ
				}

				MINI[loop] = min(MINI[loop],2*R-max_h);	//ポリゴンを収めるのに必要な、円の断片の最小の高さ

				if(DEBUG){

					printf("線分%dとの距離が%.6lf max_h:%.6lf\n",ind,mini,max_h);
					printf("高さ:%.3lf\n",2*R-max_h);
				}

				//baseを中心に図形を回転させる
				double LEFT = -M_PI,RIGHT = M_PI;
				double mid[3];

				for(int J = 0; J < 45; J++){

					mid[1] = (2.0*LEFT+RIGHT)/3.0;
					mid[2] = (1.0*LEFT+2.0*RIGHT)/3.0;

					if(DEBUG){
					printf("\nmid[1]:%.6lf mid[2]:%.6lf\n",mid[1],mid[2]);
					}

					double dist1 = 2*R,dist2 = 2*R;

					for(int c = 0; c < 2; c++){

						Polygon tmp_poly;
						bool all_IN = true;
						for(int d = 0; d < N[loop]; d++){ //4000*50*40 = 800万

							Point tmp_p = rotate(input[loop][base],input[loop][d],mid[c+1]);
							double work_dist = calc_dist(vec[k],tmp_p);
							if(work_dist > R+EPS){

								all_IN = false;
								break;
							}
							tmp_poly.push_back(tmp_p);
						}

						if(!all_IN){

							continue;
						}

						if(DEBUG){
						printf("■■円に収まった c:%d■■\n",c);
						}

						mini = R;

						//回転させた図形と、円の中心との距離を見る
						for(int a = 0; a < N[loop]; a++){

							Line calc_line = Line(tmp_poly[a],tmp_poly[(a+1)%N[loop]]);
							double work_dist = getDistanceSP(calc_line,vec[k]);

							/*if(DEBUG){
								printf("線分\n");
								calc_line.outPut();
								printf("tmp_dist:%.3lf\n",work_dist);
							}*/
							if(mini > work_dist+EPS){

								mini = work_dist;
								ind = a;
							}
						}

						double tmp_h,tmp_d;

						if(contains(tmp_poly,vec[k])){

							tmp_h = R-mini; //円の断片の最大高さ
							tmp_d = 2*R-tmp_h;

						}else{

							tmp_h = R+mini; //円の断片の最大高さ
							tmp_d = 2*R-tmp_h;
						}

						if(c == 0){

							dist1 = tmp_d;
						}else{

							dist2 = tmp_d;
						}
					}

					if(fabs(dist1-2*R) < EPS && fabs(dist2-2*R) < EPS){

						LEFT = mid[1];
						RIGHT = mid[2];
						continue;
					}

					if(DEBUG){
					printf("dist1:%.6lf dist2:%.6lf\n",dist1,dist2);
					}

					MINI[loop] = min(MINI[loop],min(dist1,dist2));

					if(dist1 < dist2){

						RIGHT = mid[2];
					}else{

						LEFT = mid[1];
					}
				}
			}
		}
	}

	if(DEBUG){

		printf("R:%.6lf 2*R:%.6lf MINI[A]:%.6lf MINIT[B]:%.6lf 2*R-(A+B):%.6lf\n",R,2*R,MINI[A],MINI[B],2*R-(MINI[A]+MINI[B]));

		if(MINI[A]+MINI[B] <= 2*R+EPS){

			printf("OK\n");
		}else{

			printf("不可\n");
		}
	}

	return MINI[A]+MINI[B] <= 2*R+EPS;

}


void func(){

	input[A].clear();
	input[B].clear();

	for(int i = 0; i < 2; i++){
		for(int k = 0; k < SIZE; k++){

			vert_line[i][k].clear();
		}
	}

	double x,y;

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

		scanf("%lf %lf",&x,&y);
		input[A].push_back(Point(x,y));
	}

	scanf("%d",&N[B]);

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

		scanf("%lf %lf",&x,&y);
		input[B].push_back(Point(x,y));
	}

	double maxi = 0;

	for(int loop = 0; loop < 2; loop++){
		for(int i = 0; i < N[loop]-1; i++){
			for(int k = i+1; k < N[loop]; k++){

				double tmp_dist = calc_dist(input[loop][i],input[loop][k]);
				maxi = max(maxi,tmp_dist);
			}
		}
	}

	for(int loop = 0; loop < 2; loop++){
		for(int i = 0; i < N[loop]; i++){

			Point a = input[loop][i];
			Point b = input[loop][(i+1)%N[loop]];

			LINE[loop][i] = Line(a,b);
		}
	}

	if(DEBUG){
	printf("maxi:%.10lf\n",maxi);
	}

	//各基準点ごとに垂直二等分線を求める
	for(int loop = 0; loop < 2; loop++){
		for(int base = 0; base < N[loop]; base++){
			for(int adj = 0; adj < N[loop]; adj++){
				if(adj == base)continue;

				Point p = input[loop][base];
				Point q = input[loop][adj];

				Point mid_p = (p+q)/2;

				Line tmp_line;

				if(fabs(p.x-q.x) < EPS){ //垂直

					//垂直二等分線
					tmp_line.p[0] = Point(mid_p.x-NUM,mid_p.y);
					tmp_line.p[1] = Point(mid_p.x+NUM,mid_p.y);

				}else if(fabs(p.y-q.y) < EPS){ //水平

					tmp_line.p[0] = Point(mid_p.x,mid_p.y+NUM);
					tmp_line.p[1] = Point(mid_p.x,mid_p.y-NUM);

				}else{

					double tmp_slope = calc_slope(Line(p,q));

					if(p.x > q.x){

						swap(p,q);
					}

					double vert_slope = -1.0/tmp_slope;

					tmp_line.p[0] = Point(mid_p.x-NUM,mid_p.y-NUM*vert_slope);
					tmp_line.p[1] = Point(mid_p.x+NUM,mid_p.y+NUM*vert_slope);
				}

				vert_line[loop][base].push_back(tmp_line);
			}
		}
	}


	if(DEBUG){
		isOK(13);
		return;
	}

	//半径を二分探索
	double left = maxi/2,right = 2001,mid = (left+right)/2;
	double ans = 2001;
	double pre = BIG_NUM;

	for(int loop = 0; loop < 50; loop++){

		if(fabs(pre-mid) < 1e-8)break;
		pre = mid;

		if(isOK(mid)){

			ans = mid;
			right = mid;
		}else{

			left = mid;
		}
		mid = (left+right)/2;
	}

	printf("%.10lf\n",ans*2);
}


int main(){

	while(true){

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

		func();
	}

	return 0;
}
accuracy: 1
time_ms: 7660
memory_kb: 7640
final_rank: 20