using System;
using System.Collections.Generic;
using System.Linq;
class Program
{
static string InputPattern = "InputX";
static List<string> GetInputList()
{
var WillReturn = new List<string>();
if (InputPattern == "Input1") {
WillReturn.Add("4");
WillReturn.Add("0 0");
WillReturn.Add("0 1");
WillReturn.Add("1 0");
WillReturn.Add("1 1");
//4.000000000000
}
else if (InputPattern == "Input2") {
WillReturn.Add("7");
WillReturn.Add("2 5");
WillReturn.Add("2 3");
WillReturn.Add("4 1");
WillReturn.Add("1 1");
WillReturn.Add("7 2");
WillReturn.Add("5 3");
WillReturn.Add("6 5");
//18.870481592668
}
else {
string wkStr;
while ((wkStr = Console.ReadLine()) != null) WillReturn.Add(wkStr);
}
return WillReturn;
}
static int mN;
static int mAllBitOn;
static int UB;
struct XYInfoDef
{
internal int X;
internal int Y;
}
static List<XYInfoDef> mXYInfoList = new List<XYInfoDef>();
static void Main()
{
List<string> InputList = GetInputList();
int[] wkArr = { };
Action<string> SplitAct = pStr =>
wkArr = pStr.Split(' ').Select(pX => int.Parse(pX)).ToArray();
mN = int.Parse(InputList[0]);
mAllBitOn = (1 << mN) - 1;
foreach (string EachStr in InputList.Skip(1)) {
SplitAct(EachStr);
XYInfoDef WillAdd;
WillAdd.X = wkArr[0];
WillAdd.Y = wkArr[1];
mXYInfoList.Add(WillAdd);
}
UB = mXYInfoList.Count - 1;
var AnswerKouho = new List<double>();
for (int I = 0; I <= UB; I++) {
AnswerKouho.Add(ExecTSP(I));
}
Console.WriteLine(AnswerKouho.Min());
}
// 開始位置を引数としてTSPの最小コストを返す
static double ExecTSP(int pStaInd)
{
// コスト[訪問済BitSet,現在位置] なインラインDP表
double?[,] DPArr = new double?[mAllBitOn + 1, UB + 1];
DPArr[0, pStaInd] = 0;
for (int I = 0; I <= mAllBitOn; I++) {
for (int J = 0; J <= UB; J++) {
if (DPArr[I, J].HasValue == false) continue;
for (int K = 0; K <= UB; K++) {
int CurrBit = (1 << K);
if ((I & CurrBit) > 0) continue;
int NewI = I + CurrBit;
// 最後の移動先は、ゴールノードの必要あり
if (NewI != mAllBitOn && K == pStaInd) continue;
double NewVal = DPArr[I, J].Value;
int CurrX = mXYInfoList[J].X;
int CurrY = mXYInfoList[J].Y;
int NextX = mXYInfoList[K].X;
int NextY = mXYInfoList[K].Y;
int XDiff = CurrX - NextX;
int YDiff = CurrY - NextY;
NewVal += Math.Sqrt(XDiff * XDiff + YDiff * YDiff);
if (DPArr[NewI, K].HasValue) {
if (DPArr[NewI, K] <= NewVal) {
continue;
}
}
DPArr[NewI, K] = NewVal;
}
}
}
return DPArr[mAllBitOn, pStaInd].Value;
}
}