import java.io.OutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.PrintWriter; import java.util.Arrays; import java.io.BufferedWriter; import java.util.InputMismatchException; import java.io.IOException; import java.io.Writer; import java.io.OutputStreamWriter; import java.io.InputStream; /** * Built using CHelper plug-in * Actual solution is at the top */ public class cut_it_out_lewin { public static void main(String[] args) { InputStream inputStream = System.in; OutputStream outputStream = System.out; InputReader in = new InputReader(inputStream); OutputWriter out = new OutputWriter(outputStream); CutItOut solver = new CutItOut(); solver.solve(1, in, out); out.close(); } static class CutItOut { int a; int b; Point[] pa; Point[] pb; Point[][] es; double[][] dp; public void solve(int testNumber, InputReader in, OutputWriter out) { a = in.nextInt(); pa = new Point[a]; for (int i = 0; i < a; i++) { pa[i] = new Point(in.nextInt(), in.nextInt()); } b = in.nextInt(); pb = new Point[b]; for (int i = 0; i < b; i++) { pb[i] = new Point(in.nextInt(), in.nextInt()); } es = new Point[b][2]; for (int i = 0; i < b; i++) { Segment s1 = new Segment(pb[i], pb[(i + 1) % b]); for (int j = 0; j < a; j++) { if (Utils.ccw(pb[i], pb[(i + 1) % b], pa[j]) && !Utils.ccw(pb[i], pb[(i + 1) % b], pa[(j + 1) % a])) { es[i][1] = getIntersect(s1, new Segment(pa[j], pa[(j + 1) % a])); } if (!Utils.ccw(pb[i], pb[(i + 1) % b], pa[j]) && Utils.ccw(pb[i], pb[(i + 1) % b], pa[(j + 1) % a])) { es[i][0] = getIntersect(s1, new Segment(pa[j], pa[(j + 1) % a])); } } } dp = new double[b][b]; AUtils.deepFill(dp, -1); double ans = 1L << 60; for (int i = 0; i < b; i++) { for (int j = 0; j < b; j++) { if (i == j) continue; Segment s1 = getSeg(es[i]); Segment s2 = getSeg(es[j], s1); ans = Math.min(ans, s1.length + s2.length + dp(i, j) + dp(j, i)); } } out.printf("%.10f\n", ans); } double dp(int from, int to) { if (dp[from][to] != -1) return dp[from][to]; if ((from + 1) % b == to) return 0; Segment s1 = getSeg(es[from]), s2 = getSeg(es[to]); double ans = 1L << 60; for (int cut = (from + 1) % b; cut != to; cut = (cut + 1) % b) { Segment r = getSeg(es[cut], s1, s2); ans = Math.min(ans, r.length + dp(from, cut) + dp(cut, to)); } return dp[from][to] = ans; } Segment getSeg(Point[] ss, Segment... ms) { Segment s1 = new Segment(ss[0], ss[1]); for (Segment s : ms) { Point t = getIntersect(s1, s); if (t == null) continue; if (Utils.ccw(s.a, s.b, s1.a)) { s1 = new Segment(t, s1.b); } else if (Utils.ccw(s.a, s.b, s1.b)) { s1 = new Segment(s1.a, t); } } return s1; } Point getIntersect(Segment s1, Segment s2) { // s1 can be extended Line l1 = new Line(s1.a, s1.b), l2 = new Line(s2.a, s2.b); if (l1.same_line(l2)) throw new RuntimeException(); if (l1.parallel(l2)) return null; Point p = l1.intersection_point(l2); return Utils.point_in_box(p, s2.a, s2.b) ? p : null; } } static class Point implements Comparable { public static double eps = 1e-10; double x; double y; public Point(double x, double y) { this.x = x; this.y = y; } public String toString() { return String.format("%.6f %.6f", x, y); } public boolean equals(Object obj) { Point o = (Point) obj; return Math.abs(x - o.x) < eps && Math.abs(y - o.y) < eps; } public int compareTo(Point o) { if (Math.abs(x - o.x) > eps) { return x < o.x ? -1 : 1; } if (Math.abs(y - o.y) > eps) { return y < o.y ? -1 : 1; } return 0; } } static class OutputWriter { private final PrintWriter writer; public OutputWriter(OutputStream outputStream) { writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(outputStream))); } public OutputWriter(Writer writer) { this.writer = new PrintWriter(writer); } public void printf(String format, Object... objects) { writer.printf(format, objects); } public void close() { writer.close(); } } static class AUtils { public static void deepFill(double[][] x, double val) { for (double[] y : x) deepFill(y, val); } public static void deepFill(double[] x, double val) { Arrays.fill(x, val); } } static class InputReader { private InputStream stream; private byte[] buf = new byte[1 << 16]; private int curChar; private int numChars; public InputReader(InputStream stream) { this.stream = stream; } public int read() { if (this.numChars == -1) { throw new InputMismatchException(); } else { if (this.curChar >= this.numChars) { this.curChar = 0; try { this.numChars = this.stream.read(this.buf); } catch (IOException var2) { throw new InputMismatchException(); } if (this.numChars <= 0) { return -1; } } return this.buf[this.curChar++]; } } public int nextInt() { int c; for (c = this.read(); isSpaceChar(c); c = this.read()) { ; } byte sgn = 1; if (c == 45) { sgn = -1; c = this.read(); } int res = 0; while (c >= 48 && c <= 57) { res *= 10; res += c - 48; c = this.read(); if (isSpaceChar(c)) { return res * sgn; } } throw new InputMismatchException(); } public static boolean isSpaceChar(int c) { return c == 32 || c == 10 || c == 13 || c == 9 || c == -1; } } static class Utils { public static final double EPS = 1e-10; public static final int INF = Integer.MAX_VALUE >> 2; public static double distance(Point a, Point b) { return fastHypot(a.x - b.x, a.y - b.y); } public static boolean point_in_box(Point p, Point b1, Point b2) { return ((p.x >= Math.min(b1.x, b2.x) - EPS) && (p.x <= Math.max(b1.x, b2.x) + EPS) && (p.y >= Math.min(b1.y, b2.y) - EPS) && (p.y <= Math.max(b1.y, b2.y) + EPS)); } public static boolean ccw(Point p, Point q, Point r) { return (r.y - p.y) * (q.x - p.x) > (q.y - p.y) * (r.x - p.x); } public static double fastHypot(double x, double y) { return Math.sqrt(x * x + y * y); } } static class Segment { public Point a; public Point b; public double length; public Segment(Point a, Point b) { this.a = a; this.b = b; length = Utils.distance(a, b); } } static class Line { public double a; public double b; public double c; public Line(double a, double b, double c) { this.a = a; this.b = b; this.c = c; } public Line(Point p1, Point p2) { // two points if (p1.x == p2.x) { a = 1; b = 0; c = -p1.x; } else { b = 1; a = -(p1.y - p2.y) / (p1.x - p2.x); c = -(a * p1.x) - (b * p1.y); } } public Line(Point p, double m) { a = -m; b = 1; c = -((a * p.x) + (b * p.y)); } public boolean parallel(Line l) { return (Math.abs(a - l.a) <= Utils.EPS && Math.abs(b - l.b) <= Utils.EPS); } public boolean same_line(Line l) { return (parallel(l) && Math.abs(c - l.c) <= Utils.EPS); } public Point intersection_point(Line l) { Point p = new Point(Utils.INF, Utils.INF); if (same_line(l)) return p; if (parallel(l)) return null; p.x = (l.b * c - b * l.c) / (l.a * b - a * l.b); if (Math.abs(b) > Utils.EPS) p.y = -(a * p.x + c) / b; else p.y = -(l.a * p.x + l.c) / l.b; return p; } } }