Problem: Problem

Chocolate company Chinor Choco has decided to build n new stores.
For each store, ask each store manager to prepare two candidates for the place you want to build, and build it in either place.

Chinor Choco sells m types of chocolate, each manufactured at a different factory.
All types of chocolate are sold at all stores.
Chinor Choco owns only one truck to transport chocolate, and one truck can only carry one store's worth of chocolate.
Therefore, trucks need to go around all factories when moving from one store to another.

Find the maximum travel distance when the stores are arranged so that the maximum minimum travel distance when moving from one store to another is the minimum.

There can be multiple stores and factories in the same location.

Constraints

The input satisfies the following conditions.

* 2 ≤ n ≤ 200
* 1 ≤ m ≤ 15
* 0 ≤ ai, bi, ci, di, xi, yi ≤ 1000

Input

The input is given in the following format.


n m
a0 b0 c0 d0
...
an−1 bn−1 cn−1 dn−1
x0 y0
...
xm−1 ym−1


All inputs are given as integers.
On the first line, the number of Chinor chocolate shops n and the number of chocolate manufacturing factories m are given, separated by blanks.
From the second line to the nth line, the coordinates (ai, bi), (ci, di) of the candidate places to build each store are given separated by blanks.
2 & plus; Factory coordinates (xi, yi) are given from the nth line to the mth line, separated by blanks.

Output

Output the maximum travel distance when the store is arranged so that the maximum of the minimum travel distance is minimized.
The error should not exceed 10-6.

Examples

Input

2 1
0 0 5 5
3 3 6 6
2 2


Output

4.2426406871


Input

2 2
0 0 6 0
7 0 3 0
4 0
5 0


Output

3.0000000000

Solution (in CPP):

Solution:
#include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 1000000000000000000
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;



#define SIZE 205

struct LOC{

	double x,y;
};

int N,M;
int POW[16];
double dp[15][1<<15][15];
double min_dist[SIZE][SIZE][2][2];
LOC shop[SIZE][2],factory[15];


//scc
int group_index;
bool check[2*SIZE];
int table[2*SIZE];
vector<int> G[2*SIZE];
vector<int> reverse_G[2*SIZE];
stack<int> S;

void dfs(int node_id){
	check[node_id] = true;

	for(int i = 0; i < G[node_id].size(); i++){
		if(!check[G[node_id][i]])dfs(G[node_id][i]);
	}
	S.push(node_id);
}

void reverse_dfs(int node_id){
	check[node_id] = true;

	table[node_id] = group_index;

	for(int i = 0; i < reverse_G[node_id].size(); i++){
		if(!check[reverse_G[node_id][i]])reverse_dfs(reverse_G[node_id][i]);
	}
}

bool is_OK(){

	for(int i = 0; i < 2*N; i++)check[i] = false;

	//まずは帰りがけ順を計算
	for(int i = 0; i < 2*N;i++){
		if(!check[i])dfs(i);
	}

	for(int i = 0; i < 2*N;i++)check[i] = false;

	group_index = -1;
	//ノードを、帰りがけ順の逆順に、各強連結成分(グループ)に分解
	while(!S.empty()){
		if(!check[S.top()]){
			group_index++;

			reverse_dfs(S.top());
		}
		S.pop();
	}

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

		if(table[i] == table[i+N])return false;
	}

	return true;
}

double calc_dist(LOC a,LOC b){

	return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}


int main(){

	POW[0] = 1;
	for(int i = 1; i <= 15; i++){

		POW[i] = POW[i-1]*2;
	}

	scanf("%d %d",&N,&M);

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

			scanf("%lf %lf",&shop[i][k].x,&shop[i][k].y);
		}
	}

	for(int i = 0; i < M; i++){

		scanf("%lf %lf",&factory[i].x,&factory[i].y);
	}

	for(int start = 0; start < M; start++){
		for(int state = 0; state < POW[M]; state++){
			for(int last = 0; last < M; last++){

				dp[start][state][last] = BIG_NUM;
			}
		}
		dp[start][POW[start]][start] = 0;
	}

	for(int start = 0; start < M; start++){
		for(int state = 0; state < POW[M]; state++){
			for(int last = 0; last < M; last++){
				if(fabs(dp[start][state][last]-BIG_NUM) < EPS)continue;

				for(int next = 0; next < M; next++){
					if(state & POW[next])continue;

					int next_state = state+POW[next];
					double next_dist = dp[start][state][last]+calc_dist(factory[last],factory[next]);

					dp[start][next_state][next] = min(dp[start][next_state][next],next_dist);
				}
			}
		}
	}

	for(int i = 0; i < N; i++){
		for(int k = 0; k < N; k++){
			if(k == i)continue;
			for(int a = 0; a < 2; a++){
				for(int b = 0; b < 2; b++){
					min_dist[i][k][a][b] = BIG_NUM;

					for(int start = 0; start < M; start++){
						for(int goal = 0; goal< M; goal++){

							double tmp_dist = calc_dist(shop[i][a],factory[start])+calc_dist(shop[k][b],factory[goal]);
							tmp_dist += dp[start][POW[M]-1][goal];

							min_dist[i][k][a][b] = min(min_dist[i][k][a][b],tmp_dist);
						}
					}
				}
			}
		}
	}

	double left = 0,right = 100000,mid = (left+right)/2;
	double ans = BIG_NUM;

	while(left+EPS < right){

		for(int i = 0; i < 2*SIZE; i++){
			G[i].clear();
			reverse_G[i].clear();
		}

		for(int i = 0; i < N; i++){
			for(int k = 0; k < N; k++){
				if(k == i)continue;
				for(int a = 0; a < 2; a++){
					for(int b = 0; b < 2; b++){

						if(min_dist[i][k][a][b] > mid){ //a→bへはパスを張れない

							int from = i;
							if(a == 1){

								from += N;
							}
							int to = k;
							if(b == 0){ //bが候補0→候補1に辺を張る,bが候補1→候補0に辺を張る

								to += N;
							}
							G[from].push_back(to);
							reverse_G[to].push_back(from);
						}
					}
				}
			}
		}

		if(is_OK()){

			ans = mid;
			right = mid-EPS;
		}else{

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

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

	return 0;
}