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>
using namespace std;
using ll = long long;
#define rep(i,n) for(int (i)=0;(i)<(int)(n);++(i))
#define all(x) (x).begin(),(x).end()
#define pb push_back
#define fi first
#define se second
#define dbg(x) cout<<#x" = "<<((x))<<endl
template<class T,class U> ostream& operator<<(ostream& o, const pair<T,U> &p){o<<"("<<p.fi<<","<<p.se<<")";return o;}
template<class T> ostream& operator<<(ostream& o, const vector<T> &v){o<<"[";for(T t:v){o<<t<<",";}o<<"]";return o;}

struct P{
    int x,y;
};

using pp = pair<P,P>;

P READ_P(){
    int x,y;
    cin >>x >>y;
    return {x,y};
}

double calc_dist(P p, P q){
    double X = abs(p.x-q.x);
    double Y = abs(p.y-q.y);
    return sqrt(X*X + Y*Y);
}

const int N = 15;
const double INF = 1e8;

double dist[N][N];

double d[N][N];
double dp[1<<N][N];

void calc(int start, int n){
    fill(dp[0],dp[1<<N],INF);
    dp[1<<start][start] = 0;
    rep(mask,1<<n){
        rep(i,n)if(mask>>i&1){
            rep(j,n)if(!(mask>>j&1)){
                int nmask = mask|(1<<j);
                dp[nmask][j] = min(dp[nmask][j], dp[mask][i]+dist[i][j]);
            }
        }
    }

    rep(i,n) d[start][i] = dp[(1<<n)-1][i];
}

struct SCC{
    int V;
    vector<vector<int>> G, rG;
    vector<int> vs; // 帰りがけ順の並び
    vector<int> cmp; //属する強連結成分トポロジカル順序
    vector<bool> used;

    SCC(){}
    SCC(int n){
        V = n;
        G = vector<vector<int>>(n);
        rG = vector<vector<int>>(n);
    }

    void add_edge(int from, int to){
        G[from].push_back(to);
        rG[to].push_back(from);
    }

    void dfs(int v){
        used[v] = true;
        rep(i,G[v].size())if(!used[G[v][i]]) dfs(G[v][i]);
        vs.push_back(v);
    }

    void rdfs(int v, int k){
        used[v]=true;
        cmp[v]=k;
        rep(i,rG[v].size())if(!used[rG[v][i]]) rdfs(rG[v][i],k);
    }

    int scc(){
        used = vector<bool>(V,false);
        vs.clear();
        rep(i,V)if(!used[i]) dfs(i);

        used = vector<bool>(V,false);
        cmp = vector<int>(V);
        int num_scc = 0;
        for(int i=vs.size()-1; i>=0; --i)if(!used[vs[i]]) rdfs(vs[i],num_scc++);
        return num_scc;
    }
};

struct TwoSat{
    int v;
    SCC graph;

    // v literals
    // 0~v-1: true
    // v~2v-1: false

    TwoSat(int num_literal){
        v = num_literal;
        graph = SCC(2*v);
    }

    inline int num(int id, bool b){return id+(b?0:v);}

    void add_clause(int x, bool X, int y, bool Y){
        graph.add_edge(num(x,!X), num(y,Y));
        graph.add_edge(num(y,!Y), num(x,X));
    }

    // 割り当てが可能か調べる
    bool calc(){
        graph.scc();
        rep(i,v)if(graph.cmp[i]==graph.cmp[v+i]) return false;
        return true;
    }

    // リテラルの真偽値を返す
    vector<bool> get_literals(){
        assert(calc());
        vector<bool> res(v);
        rep(i,v) res[i] = (graph.cmp[i]>graph.cmp[v+i]);
        return res;
    }
};

double D[200][2][200][2];

int main(){
    int n,m;
    cin >>n >>m;

    vector<vector<P>> store(n);
    rep(i,n)rep(j,2) store[i].pb(READ_P());

    vector<P> factory(m);
    rep(i,m) factory[i] = READ_P();

    rep(i,m)rep(j,m) dist[i][j] = calc_dist(factory[i],factory[j]);
    rep(i,m) calc(i,m);

    rep(i,n)rep(j,i)rep(ii,2)rep(jj,2){
        double tt = INF;
        rep(from,m)rep(to,m){
            double tmp = calc_dist(store[i][ii], factory[from]);
            tmp += d[from][to];
            tmp += calc_dist(factory[to], store[j][jj]);
            tt = min(tt,tmp);
        }
        D[i][ii][j][jj] = tt;
    }

    auto valid = [&](double lim){
        TwoSat solver(n);
        rep(i,n)rep(j,i)rep(ii,2)rep(jj,2){
            if(D[i][ii][j][jj]>lim) solver.add_clause(i,!ii,j,!jj);
        }
        return solver.calc();
    };

    double l=0, r=INF;
    rep(_,60){
        double mid=(l+r)/2;
        if(valid(mid)) r=mid;
        else l=mid;
    }
    printf("%.10f\n", r);
    return 0;
}