#include <algorithm>
#include <bitset>
#include <complex>
#include <deque>
#include <exception>
#include <fstream>
#include <functional>
#include <iomanip>
#include <ios>
#include <iosfwd>
#include <iostream>
#include <istream>
#include <iterator>
#include <limits>
#include <list>
#include <locale>
#include <map>
#include <memory>
#include <new>
#include <numeric>
#include <ostream>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <stdexcept>
#include <streambuf>
#include <string>
#include <typeinfo>
#include <utility>
#include <valarray>
#include <vector>
#include <cstring>

/* 
PascalCase  クラス名
camelCase   メソッド名，関数名，変数名
snake_case  ファイル名，名前空間，std のメソッド名，変数名，型名に準じる場合
SNAKE_CASE	マクロ名，static const 定数，列挙体
*/

#define REP(i, n) for (int i = 0; i < (n); i++)
#define FOR(i, init, n) for (int i = init; i < (n); i++)
#define ALL(obj) (obj).begin(), (obj).end()
#define RALL(obj) (obj).rbegin(), (obj).rend()
#define Cout(obj) cout << obj << endl
#define Size(obj) (int)(obj).size()
#define fcout cout << fixed << setprecision(10)
#define fi first
#define se second

using namespace std;
using ll = long long int;

const int MOD = 1e9 + 7;
const int iINF = 1e9;
const long long int llINF = 1e18;
const double PI = acos(-1.0);

const int dx[4] = {1, 0, -1, 0};
const int dy[4] = {0, 1, 0, -1};

double EPS = 1e-10;

double add(double a, double b)
{
    if(abs(a + b) < EPS * (abs(a) + abs(b))) return 0;

    return a + b;
}

struct P 
{
    double x, y;
    int id;

    P() {};
    P(double x, double y) : x(x), y(y) {}

    P operator + (P p)
    {
        return P(add(x, p.x), add(y, p.y));
    }

    P operator - (P p)
    {
        return P(add(x, -p.x), add(y, -p.y));
    }

    P operator * (double d)
    {
        return P(x * d, y * d);
    }

    double dot(P p)
    {
        return add(x * p.x, y * p.y);
    }

    double det(P p)
    {
        return add(x * p.y, -y * p.x);
    }

    bool operator < (const P& p)
    {
        if(x != p.x) return x < p.x;

        return y < p.y;
    }
};

vector<P> convexHull(vector<P> ps)
{
    sort(ALL(ps));
    int n = Size(ps);
    int k = 0;
    vector<P> qs(n * 2);

    REP(i, n)
    {
        while(k > 1 && (qs[k - 1] - qs[k - 2]).det(ps[i] - qs[k - 1]) <= 0) k--;
        qs[k++] = ps[i];
    }

    for(int i = n - 2, t = k; i >= 0; i--)
    {
        while(k > t && (qs[k - 1] - qs[k - 2]).det(ps[i] - qs[k - 1]) <= 0) k--;
        qs[k++] = ps[i];
    }

    qs.resize(k - 1);
    return qs;

}

class UnionFind
{
  private:
    vector<int> par;
    vector<int> sizes;

  public:
    UnionFind(int N) : par(N), sizes(N, 1)
    {
        REP(i, N)
        par[i] = i;
    }

    int find(int x)
    {
        if (x == par[x])
            return x;

        return par[x] = find(par[x]);
    }

    void unite(int x, int y)
    {
        x = find(x);
        y = find(y);

        if (x == y)
            return;

        if (sizes[x] < sizes[y])
            swap(x, y);

        par[y] = x;
        sizes[x] += sizes[y];
    }

    bool same(int x, int y)
    {
        return find(x) == find(y);
    }

    int size(int x)
    {
        return sizes[find(x)];
    }
};

struct edge
{
    int from, to;
    double cost;

    edge(int from, int to, double cost) : to(to), from(from), cost(cost){};

    bool operator<(const edge &e)
    {
        return cost < e.cost;
    }
};

int main()
{
    cin.tie(0);
    ios::sync_with_stdio(false);

    int V, R;
    cin >> V >> R;

    vector<P> vec;
    map<P, int> mp;

    REP(i, V)
    {
        double x, y;
        cin >> x >> y;
        P p = P(x, y);
        p.id = i;
        vec.push_back(p);
    }

    vector<pair<int, int>> roads(R);

    REP(i, R)
    {
        cin >> roads[i].fi >> roads[i].se;
    }

    vector<P> conv = convexHull(vec);

    double ans = 0.0;

    REP(i, Size(conv))
    {
        double a = abs(conv[(i + 1) % Size(conv)].x - conv[i].x);
        double b = abs(conv[(i + 1) % Size(conv)].y - conv[i].y);
        ans += sqrt(pow(a, 2) + pow(b, 2));
    }

    UnionFind uf(V);

    REP(i, Size(conv) - 1)
    {
        uf.unite(conv[i].id, conv[i + 1].id);
    }

    //クラスカル法

    vector<edge> edges;

    REP(i, V)
    {
        for (int j = i + 1; j < V; j++)
        {
            double dx = abs(vec[i].x - vec[j].x);
            double dy = abs(vec[i].y - vec[j].y);
            double cost = sqrt(pow(dx, 2) + pow(dy, 2));
            edges.push_back(edge(i, j, cost));
        }
    }

    sort(ALL(edges));

    REP(i, Size(edges))
    {
        edge e = edges[i];

        for (auto r : roads)
        {
            if ((r.fi - 1 == e.to && r.se - 1 == e.from) || (r.fi - 1 == e.from && r.se - 1 == e.to))
            {
                if (uf.same(e.from, e.to))
                    continue;

                ans += e.cost;

                uf.unite(e.from, e.to);
            }
        }
    }

    fcout << ans << endl;

    return 0;
}


Measured memory_bytes: 3440