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 JAVA (judge verdict: Accepted)



import java.util.Arrays;
import java.util.Scanner;

class Main {
	double[][] p = new double[2][6];

	void run() {
		Scanner sc = new Scanner(System.in);
		int Na = sc.nextInt();
		int Nb = sc.nextInt();
		long[] xa = new long[Na];
		long[] ya = new long[Na];
		long[] xb = new long[Nb];
		long[] yb = new long[Nb];
		for (int i = 0; i < Na; ++i) {
			xa[i] = sc.nextLong();
			ya[i] = sc.nextLong();
		}
		for (int i = 0; i < Nb; ++i) {
			xb[i] = sc.nextLong();
			yb[i] = sc.nextLong();
		}

		double ans = Double.MAX_VALUE / 3;
		for (int t = 0; t < 2; ++t) {
			for (int i = 0; i < Na; ++i) {
				for (int j = 0; j < Na; ++j) {
					if (cross(xa[0], ya[0], xa[i], ya[i], xb[0], yb[0], xb[1], yb[1])) {
						continue;
					}
					if (cross(xa[i], ya[i], xa[j], ya[j], xb[0], yb[0], xb[1], yb[1])) {
						continue;
					}
					if (cross(xa[j], ya[j], xa[1], ya[1], xb[0], yb[0], xb[1], yb[1])) {
						continue;
					}
					ans = Math.min(ans, dist(xa[0], ya[0], xa[i], ya[i]) + dist(xa[i], ya[i], xa[j], ya[j])
							+ dist(xa[j], ya[j], xa[1], ya[1]) + dist(xb[0], yb[0], xb[1], yb[1]));
				}
			}
			Na ^= Nb;
			Nb ^= Na;
			Na ^= Nb;
			long[] tmp = new long[Na];
			tmp = Arrays.copyOf(xa, xa.length);
			xa = Arrays.copyOf(xb, xb.length);
			xb = Arrays.copyOf(tmp, tmp.length);
			tmp = Arrays.copyOf(ya, ya.length);
			ya = Arrays.copyOf(yb, yb.length);
			yb = Arrays.copyOf(tmp, tmp.length);
		}
		System.out.println(ans >= Double.MAX_VALUE / 4 ? "-1" : ans);
	}

	double dist(long xa, long ya, long xb, long yb) {
		long dx = xa - xb;
		long dy = ya - yb;
		return Math.sqrt(dx * dx + dy * dy);
	}

	boolean cross(long xa1, long ya1, long xb1, long yb1, long xa2, long ya2, long xb2, long yb2) {
		long v = f(xa1, ya1, xb1, yb1, xa2, ya2) * f(xa1, ya1, xb1, yb1, xb2, yb2);
		long u = f(xa2, ya2, xb2, yb2, xa1, ya1) * f(xa2, ya2, xb2, yb2, xb1, yb1);
		return v <= 0 && u <= 0;
	}

	long f(long xa, long ya, long xb, long yb, long x, long y) {
		return (ya - yb) * (x - xa) - (y - ya) * (xa - xb);
	}

	void tr(Object... objects) {
		System.out.println(Arrays.deepToString(objects));
	}

	public static void main(String[] args) {
		new Main().run();
	}
}