#include<complex>
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cassert>
#include<cstring>
#include<cmath>
#include<deque>
#include<vector>
#include<queue>
#include<algorithm>
#include<map>
#include<set>

#define REP(i,s,n) for(int i=s;i<n;++i)
#define rep(i,n) REP(i,0,n)
#define EPS (1e-10)
#define equals(a,b) (fabs((a)-(b)) < EPS)
#define COUNTER_CLOCKWISE 1
#define CLOCKWISE -1 
#define ONLINE_BACK 2
#define ONLINE_FRONT -2
#define ON_SEGMENT 0

using namespace std;

class Point{
public:
  double x,y;

  Point(double x = 0,double y = 0): x(x),y(y){}

  Point operator + (Point p){return Point(x+p.x,y+p.y);}
  Point operator - (Point p){return Point(x-p.x,y-p.y);}
  Point operator * (double a){return Point(a*x,a*y);}
  Point operator / (double a){return Point(x/a,y/a);}
  Point operator * (Point a){ return Point(x * a.x - y * a.y, x * a.y + y * a.x); }

  bool operator < (const Point& p) const{ return !equals(x,p.x)?x<p.x:(!equals(y,p.y)&&y<p.y); }

  bool operator == (const Point& p)const{ return fabs(x-p.x) < EPS && fabs(y-p.y) < EPS; }

};

struct Segment{
  Point p1,p2;
  Segment(Point p1 = Point(),Point p2 = Point()):p1(p1),p2(p2){}
  bool operator <  (const Segment& s) const { return ( p2 == s.p2 ) ? p1 < s.p1 : p2 < s.p2; }
  bool operator == (const Segment& s) const { return ( s.p1 == p1 && s.p2 == p2 ) || ( s.p1 == p2 && s.p2 == p1 ); }

};

typedef Point Vector;
typedef Segment Line;
typedef vector<Point> Polygon;

ostream& operator << (ostream& os,const Point& a){ return os << "(" << a.x << "," << a.y << ")"; }

ostream& operator << (ostream& os,const Segment& a){ return os << "( " << a.p1 << " , " << a.p2 << " )"; }

double dot(Point a,Point b){ return a.x*b.x + a.y*b.y; }

double cross(Point a,Point b){ return a.x*b.y - a.y*b.x; }

double norm(Point a){ return a.x*a.x+a.y*a.y; }

double abs(Point a){ return sqrt(norm(a)); }

//rad ????§???????????????¢?????§?????????????????¨
Point rotate(Point a,double rad){ return Point(cos(rad)*a.x - sin(rad)*a.y,sin(rad)*a.x + cos(rad)*a.y); }

// ??????????????¢????????????
double toRad(double agl){ return agl*M_PI/180.0; }

// a => prev, b => cur, c=> next
// prev ?????? cur ????????£??? next ????????????????§????????±???????
double getArg(Point a,Point b,Point c){
  double arg1 = atan2(b.y-a.y,b.x-a.x);
  double arg2 = atan2(c.y-b.y,c.x-b.x);
  double arg = fabs( arg1 - arg2 );
  while( arg > M_PI ) arg -= 2.0 * M_PI;
  return fabs(arg);
}

int ccw(Point p0,Point p1,Point p2){
  Point a = p1-p0;
  Point b = p2-p0;
  if(cross(a,b) > EPS)return COUNTER_CLOCKWISE;
  if(cross(a,b) < -EPS)return CLOCKWISE;
  if(dot(a,b) < -EPS)return ONLINE_BACK;
  if(norm(a) < norm(b))return ONLINE_FRONT;
  return ON_SEGMENT;
}

Polygon andrewScan(Polygon s)
{
  Polygon u,l;
  if(s.size() < 3)return s;

  sort(s.begin(),s.end());

  u.push_back(s[0]);
  u.push_back(s[1]);
  l.push_back(s[s.size()-1]);
  l.push_back(s[s.size()-2]);

  for(int i=2;i<s.size();i++)
    {
      for(int n=u.size();n >= 2 && ccw(u[n-2],u[n-1],s[i]) != CLOCKWISE; n--)
	u.pop_back();
      u.push_back(s[i]);
    }

  for(int i=s.size()-3; i>=0 ; i--)
    {
      for(int n=l.size(); n >= 2 && ccw(l[n-2],l[n-1],s[i]) != CLOCKWISE; n--)
	l.pop_back();
      l.push_back(s[i]);
    }

  reverse(l.begin(),l.end());

  for(int i = u.size()-2; i >= 1; i--) l.push_back(u[i]);

  return l;
}

typedef pair<int,int> ii;

inline bool LT(double a,double b) { return !equals(a,b) && a < b; }

vector<Point> ps;
inline bool cmp(ii &s,ii &t) { 
  Segment a = Segment(ps[s.first],ps[s.second]);
  Segment b = Segment(ps[t.first],ps[t.second]);
  return LT(abs(a.p1-a.p2),abs(b.p1-b.p2)); 
}


int par[110];

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

void unit(int x,int y) {
  x = find(x), y = find(y);
  if( x != y ) par[x] = y;
}

void compute(vector<ii> &segs) {
  Polygon poly = andrewScan(ps);
  vector<Segment> convex;
  double ans = 0;
  set<Point> S;
  set<int> used;
  vector<int> vused;
  rep(i,(int)poly.size()) {
    convex.push_back(Segment(poly[i],poly[(i+1)%(int)poly.size()]));
    ans += abs(convex.back().p1-convex.back().p2);
    rep(j,(int)ps.size()) if( ps[j] == poly[i] ) {
      used.insert(j);
      vused.push_back(j);
      break;
    }
  }

  sort(segs.begin(),segs.end(),cmp);
  rep(i,(int)ps.size()) par[i] = i;
  rep(i,(int)vused.size()-1) unit(vused[i],vused[i+1]);
  rep(i,(int)segs.size()) {
    int s = segs[i].first, t = segs[i].second;
    if( find(s) == find(t) ) continue;
    unit(s,t);
    ans += abs(ps[s]-ps[t]);
  }

  printf("%.1000f\n",ans);
}

int main() {
  int V,R;
  cin >> V >> R;
  ps.resize(V);
  rep(i,V) cin >> ps[i].x >> ps[i].y;
  vector<ii> segs(R);
  rep(i,R) {
    cin >> segs[i].first >> segs[i].second;
    --segs[i].first, --segs[i].second;
  }
  compute(segs);
  return 0;
}

Measured memory_bytes: 3268