#include <iostream>
#include <algorithm>
#include <stdio.h>
#include <math.h>
using namespace std;
const int MAXV = 1000;//最大顶点数
const int INF = 1000000000;
//n为顶点数
//MAXV为最大顶点数
int n,m;
double G[MAXV][MAXV];
double d[MAXV];// 顶点到集合S的最短距离
bool vis[MAXV] = {false};//标记数组,vis[i] == true表示已访问
double prim()
{
fill(d,d+MAXV,INF);
d[0] = 0;//只有0号顶点到集合s的距离为0,其他全为INF
double ans = 0;//存放最小生成树的边权之和
//找n个点
for(int i=0;i<n;i++)
{
int u = -1,MIN = INF;//u使d[u]最小,MIN存放该最小的d[u]
//每次找一个到集合距离最小的点
for(int j = 0;j < n;j++)
{
if(vis[j] == false && d[j] < MIN)
{
u = j;
MIN = d[j];
}
}
if( u== -1 )
{
return -1;
}
//标记u为已访问
vis[u] = true;
ans += d[u];
for(int v=0;v < n;v++)
{
//如果v未访问,且u能到达v,并且以u为中转可以是v离集合更近
if(vis[v] == false && G[u][v] != INF && G[u][v] < d[v])
{
d[v] = G[u][v] ;
}
}
}
return ans;
}
struct point
{
int x;
int y;
};
point p[MAXV];
double getDis(point &a,point &b)
{
return sqrt( (a.x - b.x)*(a.x - b.x) + (a.y - b.y)*(a.y - b.y));
}
int main()
{
cin >> n;
for(int i=0;i<n;i++)
{
cin >> p[i].x;
cin >> p[i].y;
}
//初始化图G
fill(G[0],G[0] + MAXV * MAXV,INF);
for(int i=0;i<m;i++)
{
cin >> p[i].x;
cin >> p[i].y;
}
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
G[i][j] = getDis(p[i],p[j]);
}
}
double ans = prim();
printf("%.2f \n",ans);
return 0;
}