#include <iostream>
#include <vector>
#include <map>
#include <set>
#include <queue>
#include <deque>
#include <stack>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <complex>

using namespace std;

//typedef
typedef vector<int> VI;
typedef vector<VI> VVI;
typedef vector<string> VS;
typedef pair<int, int> PII;
typedef long long ll;

#define omajinai                 \
    ios::sync_with_stdio(false); \
    cin.tie(0)
#define endll '\n'

//container util
#define ALL(a) (a).begin(), (a).end()
#define RALL(a) (a).rbegin(), (a).rend()
#define UNIQUE(a) (a).erase(unique((a).begin(), (a).end()), (a).end())
#define MP make_pair
#define SZ(a) int((a).size())
#define EACH(i, c) for (auto i = (c).begin(); i != (c).end(); ++i)
#define EXIST(s, e) ((s).find(e) != (s).end())
#define SORT(c) sort((c).begin(), (c).end())

//repetition
#define FOR(i, a, b) for (int i = (a); i < (b); ++i)
#define REP(i, n) FOR(i, 0, n)
#define RFOR(i, b, a) for (int i = (b)-1; i >= (a); --i)
#define RREP(i, n) RFOR(i, n, 0)

//clear memory
#define CLR(a) memset((a), 0, sizeof(a))

//debug
#define dump(x) cerr << "[L " << __LINE__ << "] " << #x << " = " << (x) << "\n";

typedef complex<double> P;
#define X real()
#define Y imag()
#define dot(a, b) (conj(a) * (b)).X
#define cross(a, b) (conj(a) * (b)).Y

int sqri(double a)
{
    return (int)(a * a);
}

struct edge
{
    int a, b, cost2;
    bool operator<(const edge &a) const
    {
        return cost2 < a.cost2;
    }
};

/// unionfind

int par[100], rk[100];
void init(int m)
{
    REP(i, m)
    par[i] = i;
}
int find(int a)
{
    if (a == par[a])
    {
        return a;
    }
    else
    {
        return par[a] = find(par[a]);
    }
}
bool same(int a, int b)
{
    return find(a) == find(b);
}
void unite(int a, int b)
{
    if (same(a, b))
        return;
    a = find(a);
    b = find(b);
    if (rk[a] < rk[b])
    {
        par[a] = b;
    }
    else
    {
        par[b] = a;
        if (rk[a] == rk[b])
            rk[a]++;
    }
}

///

int v, r;
int x[100], y[100];
edge es[1000];
pair<P, int> pts[100];

int dist2(int a, int b)
{
    return sqri(
               x[a] - x[b]) +
           sqri(
               y[a] - y[b]);
}

P p; // base point

namespace std
{
const bool operator<(P a, P b) // polar compare
{
    a -= p;
    b -= p;
    // a.Y/a.X < b.Y/b.X
    return a.Y * b.X < a.X * b.Y;
}
}

double ccw(P a, P b, P c)
{
    a -= b;
    c -= b;
    return cross(a, c);
}

int convex[200];

double ans;

// graham scan
// to make convex hull
int scan()
{
    int m = 0;
    sort(pts + 1, pts + v);
    REP(i, v)
    {
        while (m > 1 && ccw(pts[i].first, pts[convex[m - 2]].first, pts[convex[m - 1]].first) > 0)
            m--;
        convex[m] = i;
        m++;
    }
    REP(i, m)
    {
        int p1 = pts[convex[i]].second;
        int p2 = pts[convex[(i + 1) % m]].second;
        unite(p1, p2);
        ans += sqrt(dist2(p1, p2));
    }
    return m;
}

void kruskal()
{
    sort(es, es + r);
    REP(i, r)
    {
        int a, b, cost2;
        a = es[i].a;
        b = es[i].b;
        cost2 = es[i].cost2;

        if (!same(a, b))
        {
            unite(a, b);
            ans += sqrt(cost2);
        }
    }
}

// max dist is 2000 * root 2 < 3000
// 9 * 10^6

int main()
{
    cin >> v >> r;
    int mpy = 10000, mpi;
    REP(i, v)
    {
        cin >> x[i] >> y[i];
        pts[i] = MP(P(x[i], y[i]), i); // have point number
        if (y[i] < mpy)
        {
            mpy = y[i];
            mpi = i;
        }
    }
    swap(pts[0], pts[mpi]);
    p = pts[0].first;
    REP(i, r)
    {
        int s, t;
        cin >> s >> t;
        s--;
        t--;
        es[i] = (edge){s, t, dist2(s, t)};
    }
    init(v);
    scan();
    kruskal();
    cout << fixed << ans << endll;
}

Measured memory_bytes: 3292