Problem:
Problem E: 街を駆ける道

ネーヴァ王国には、トタタ族とツテテ族、２種類の民族が暮らしている。トタタ族の最大の特徴は、
酢豚にパイナップルを入れて食べることである。だがツテテ族は、パイナップルに酢豚を入れて食べ
る。こんな２つの民族がお互いに仲良くやっていけるはずもなく、トタタ族とツテテ族は、何百年も
の昔からずっといがみ合いを続けてきた。

そんなある日、ネーヴァ王のもとに、２つの民族から嘆願書が届いた。それによるとトタタ族は、自
分たちが暮らす街Ａと街Ｂのあいだを結ぶ道を建設してほしいらしい。一方でツテテ族も、自分たち
が暮らす街Ｃと街Ｄのあいだを結ぶ道を建設してほしいらしい。

２つの民族が衝突するのを防ぐため、トタタ族が通る道とツテテ族が通る道を交差させることはでき
ない。また、技術的な制約により、２つの街のあいだを一直線に結ぶような道しか建設することはで
きない。つまり、必要ならば街Ａと街Ｂを直接道で結ばずに、いくつかのトタタ族の街を経由して街
Ａと街Ｂを間接的に結ぶことになるだろう（もちろん、ツテテ族の街を経由してはならない）。その
際、トタタ族の街を結ぶ道どうしは交差していてもよい。街Ｃと街Ｄについても同様である。

道を建設するには、その長さに比例したコストがかかる。なので、条件をみたしつつ、できるだけ建
設する道の長さの合計が短くなるようにしたい。さて、長さの最小値はいくつになるだろうか。

Input

NA NB

xA,1 yA,1

xA,2 yA,2

.

.

.

xA,NA yA,NA

xB,1 yB,1

xB,2 yB,2

.

.

.

xB,NB yB,NB

入力の１行目には、整数NA（2 ≤ NA ≤ 1,000）と整数NB（2 ≤ NB ≤ 1,000）が、空白区切りで書かれている。これは、ネーヴァ王国にはトタタ族が暮らす街がNA 個、ツテテ族が暮らす街がNB 個あることをあらわす。初期状態では、どこにも道は建設されていない。

続くNA 行には、整数xA,i（-10,000 ≤ xA,i ≤ 10,000）と整数yA,i（-10,000 ≤ yA,i ≤ 10,000）が、空白区切りで書かれている。ネーヴァ王国の地理は２次元直交座標平面であらわされ、１＋ i 行目に書かれた整数xA,i とyA,i は、トタタ族が暮らすi 番目の街の位置座標が(xA,i, yA,i) であることをあらわす。(xA,1, yA,1) と(xA,2, yA,2) が、結ぶべき２つの街の座標である。

続くNB 行には、整数xB,i（-10,000 ≤ xB,i ≤ 10,000）と整数yB,i（-10,000 ≤ yB,i ≤ 10,000）が、空白区切りで書かれている。１＋ NA ＋ i 行目に書かれた整数xB,i とyB,i は、ツテテ族が暮らすi 番目の街の位置座標が(xB,i, yB,i) であることをあらわす。(xB,1, yB,1) と(xB,2, yB,2) が、結ぶべき２つの街の座標である。

どの２つの街の座標も異なっており、どの３つの街も同一直線上にないと仮定してよい。

Output

問題文の条件をみたすように道を建設したとき、道の長さの合計の最小値を出力せよ。ここで言う
「長さ」とは、ユークリッド距離のことである。ただし、どうやっても条件をみたす道を建設できな
いときは、代わりに-1 を出力せよ。出力は誤差を含んでいてもよいが、真の値との相対誤差が10-9未満でなければならない。

Sample Input 1

2 2
0 0
1 1
2 0
2 -1

Sample Output 1

2.414213562373

Sample Input 2

2 3
4 0
0 0
2 3
2 -2
3 1

Sample Output 2

-1

Sample Input 3

5 2
-2 1
1 2
-1 3
-1 5
1 4
0 4
0 0

Sample Output 3

12.359173603117

Solution in C++14 (judge verdict: Accepted)

#include <iostream>
#include <vector>
#include <complex>
#include <utility>
#include <algorithm>
#include <numeric>
#include <queue>
#include <iomanip>
using namespace std;
#define EPS 1e-10
#define rep(i,n) for(int i=0;i<n;i++)
typedef complex<double> C;

struct L :public vector<C>
{
    L(){}
    L(const C a, const C b){
        push_back(a);push_back(b);
    }
};
double cross(const C a,const C b){
    return imag(conj(a)*b);
}
double dot(const C a,const C b){
    return real(conj(a)*b);
}
int ccw (C a, C b, C 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 L& s,const L &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;
}

template<typename T> class Dijkstra{
    public:
    struct edge{
        int to; T cost;
    };
    int V;
    vector<vector<edge> > G;
    vector<T> d;
    using pti = pair<T,int>;
    Dijkstra(int node_size) : V(node_size),G(V),d(V,numeric_limits<T>::max()){}
    void add_edge(int u,int v,T cost){
        G[u].push_back((edge){v,cost}),G[v].push_back((edge){u,cost});
    }
    void solve(int s){
        priority_queue<pti,vector<pti>,greater<pti> > que;
        d[s] = 0;
        que.push(pti(0,s));
        while(!que.empty()){
            pti p = que.top();
            que.pop();
            int v = p.second;
            if(d[v] < p.first) continue;
            for(auto& w : G[v]){
                if(d[w.to] > d[v]+w.cost){
                    d[w.to] = d[v] + w.cost;
                    que.push(pti(d[w.to],w.to));
                }
            }
        }
    }
};


int main(){
    int a,b;
    cin >> a >> b;
    vector<complex<double> >x(a),y(b);
    for(int i=0;i<a;i++){
        double p,q;
        cin >> p >> q;
        x[i] = C(p,q);
    }
    for(int i=0;i<b;i++){
        double p,q;
        cin >> p >> q;
        y[i] = C(p,q);
    }
    Dijkstra<double> gx(a),gy(b);
    for(int i=0;i<a;i++){
        for(int j=i+1;j<a;j++){
            if(!intersectSS(L(y[0],y[1]),L(x[i],x[j]))){
                gx.add_edge(i,j,sqrt(dot(x[i]-x[j],x[i]-x[j])));
            }
        }
    }
    for(int i=0;i<b;i++){
        for(int j=i+1;j<b;j++){
            if(!intersectSS(L(x[0],x[1]),L(y[i],y[j]))){
                gy.add_edge(i,j,sqrt(dot(y[i]-y[j],y[i]-y[j])));
           }
        }
    }
    double ans = 0.0;
    gx.solve(0);
    gy.solve(0);
    ans = sqrt(dot(x[0]-x[1],x[0]-x[1])) + gy.d[1];
    ans = min(ans,sqrt(dot(y[0]-y[1],y[0]-y[1])) + gx.d[1]);
    if(ans<1000000000.00)cout <<fixed << setprecision(15) << ans << endl;
    else cout << -1 << endl;
    return 0;
}