#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <iostream>
#include <math.h>
#include <assert.h>
#include <vector>
#include <queue>
#include <string>
#include <map>
#include <set>

using namespace std;
typedef long long ll;
typedef unsigned int uint;
typedef unsigned long long ull;
static const double EPS = 1e-9;
static const double PI = acos(-1.0);

#define REP(i, n) for (int i = 0; i < (int)(n); i++)
#define FOR(i, s, n) for (int i = (s); i < (int)(n); i++)
#define FOREQ(i, s, n) for (int i = (s); i <= (int)(n); i++)
#define FORIT(it, c) for (__typeof((c).begin())it = (c).begin(); it != (c).end(); it++)
#define MEMSET(v, h) memset((v), h, sizeof(v))

#include <complex>

typedef complex<double> Point;
typedef vector<Point> Polygon;

static const double INF = 1e+10;

#define CURR(P, i) (P[i])
#define NEXT(P, i) (P[(i + 1) % P.size()])

struct Line : public vector<Point> {
  Line() {;}
  Line(Point a, Point b) { push_back(a); push_back(b); }
};

struct Circle {
  Point p;
  double r;
  Circle() {;}
  Circle(Point p, double r) : p(p), r(r) {;}
};

namespace std {
  bool operator<(const Point &lhs, const Point &rhs) {
    return lhs.real() == rhs.real() ? lhs.imag() < rhs.imag() : lhs.real() < rhs.real();
  }
}

inline double cross(const Point &a, const Point &b) {
  return imag(conj(a) * b);
}

inline double dot(const Point &a, const Point &b) {
  return real(conj(a) * b);
}

inline int ccw(Point a, Point b, Point c) {
  b -= a;
  c -= a;
  if (cross(b, c) > 0) { return 1; }
  if (cross(b, c) < 0) { return -1; }
  if (dot(b, c) < 0) { return 2; }
  if (norm(b) < norm(c)) { return -2; }
  return 0;
}


bool intersectSS(const Line &s, const Line &t) {
  return ccw(s[0], s[1], t[0]) * ccw(s[0], s[1], t[1]) <= 0 &&
    ccw(t[0], t[1], s[0]) * ccw(t[0], t[1], s[1]) <= 0;
}

typedef double Weight;
struct Edge {
  int src;
  int dest;
  Weight weight;
  Edge(int src, int dest, Weight weight) :
    src(src), dest(dest), weight(weight) {;}
  bool operator<(const Edge &rhs) const {
    return weight > rhs.weight;
  }
};

typedef vector<Edge> Edges;
typedef vector<Edges> Graph;
typedef vector<Weight> Array;
typedef vector<Array> Matrix;

Weight Dijkstra(const Graph &g, int s, int t) {
  const int n = g.size();
  vector<bool> visit(n, false);
  Array dist(n, 1e+100);
  priority_queue<Edge> que;
  que.push(Edge(s, s, 0));
  Weight ans = 1e+100;
  dist[s] = 0;
  while (!que.empty()) {
    Edge edge = que.top();
    que.pop();
    int from = edge.dest;
    if (visit[from]) { continue; }
    visit[from] = true;
    if (from == t) {
      ans = edge.weight;
      break;
    }   
    for (int i = 0; i < (int)g[from].size(); i++) {
      int to = g[from][i].dest;
      Weight ncost = edge.weight + g[from][i].weight;
      if (visit[to] || ncost >= dist[to]) { continue; }
      dist[to] = ncost;
      que.push(Edge(from, to, ncost));
    }   
  }
  return ans;
}

int n[2];
vector<Point> ps[2];

double calc() {
  double ret = 0.0;
  ret += abs(ps[1][0] - ps[1][1]);
  Line s1 = Line(ps[1][0], ps[1][1]);
  Graph g(n[0]);
  REP(i, n[0]) {
    REP(j, n[0]) {
      if (i == j || intersectSS(s1, Line(ps[0][i], ps[0][j]))) { continue; }
      g[i].push_back(Edge(i, j, abs(ps[0][i] - ps[0][j])));
    }
  }
  ret += Dijkstra(g, 0, 1);
  return ret;
}

int main() {
  while (scanf("%d %d", &n[0], &n[1]) > 0) {
    REP(iter, 2) {
      ps[iter].clear();
      REP(i, n[iter]) {
        double x, y;
        scanf("%lf %lf", &x, &y);
        ps[iter].push_back(Point(x, y));
      }
    }
    double ans = 1e+100;
    REP(iter, 2) {
      ans = min(ans, calc());
      swap(ps[0], ps[1]);
      swap(n[0], n[1]);
    }
    if (ans > 1e+10) {
      puts("-1");
    } else {
      printf("%.10f\n", ans);
    }
  }
}

Measured memory_bytes: 0