//注意下两个点的情况就很水了. 模板题
#include<stdio.h>
#include<math.h>
#include<algorithm>
#include<iostream>
using namespace std;
const int MAXN=105;//点数 //复杂度nlogn
struct point
{
int x,y;
};
point list[MAXN];
int stack[MAXN],top;
int cross(point p0,point p1,point p2) //计算叉积 p0p1 X p0p2
{
return (p1.x-p0.x)*(p2.y-p0.y)-(p1.y-p0.y)*(p2.x-p0.x);
}
double dis(point p1,point p2) //计算 p1p2的 距离
{
return sqrt((double)(p2.x-p1.x)*(p2.x-p1.x)+(p2.y-p1.y)*(p2.y-p1.y));
}
bool cmp(point p1,point p2) //极角排序函数 , 角度相同则距离小的在前面
{
int tmp=cross(list[0],p1,p2); //逆时针
if(tmp>0) return true;
else if(tmp==0&&dis(list[0],p1)<dis(list[0],p2)) return true;
else return false;
}
void init(int n) 输入,并把 最左下方的点放在 list[0] 。并且进行极角排序 list 存点,下标[0,n);
{
int i,k;
point p0;
scanf("%d%d",&list[0].x,&list[0].y);
p0.x=list[0].x;
p0.y=list[0].y;
k=0;
for(i=1;i<n;i++)
{
scanf("%d%d",&list[i].x,&list[i].y);
if( (p0.y>list[i].y) || ((p0.y==list[i].y)&&(p0.x>list[i].x)) )
{
p0.x=list[i].x;
p0.y=list[i].y;
k=i;
}
}
list[k]=list[0];
list[0]=p0;
sort(list+1,list+n,cmp);//极角排序 // 逆时针
}
void graham(int n) // stack 里存的是凸包外围点的下标. [0,top]
{
int i;
if(n==1) {top=0;stack[0]=0;}
if(n==2)
{
top=1;
stack[0]=0;
stack[1]=1;
}
if(n>2)
{
for(i=0;i<=1;i++) stack[i]=i;
top=1;
for(i=2;i<n;i++)
{
while(top>0&&cross(list[stack[top-1]],list[stack[top]],list[i])<=0) top--;//大方向 逆时针
top++; //↑==0时会去掉短的,延长出 更长的线. <0时,以top-1点为中心,
stack[top]=i; //↑连接top点和当前i点. 若转向为顺时针, 那就去掉top点. 这样保证是最外的.
}
}
}
double sumlen()//自己打的画蛇添竹的周长计算函数
{ // 如果只有两个点, 呵呵. 要注意要不要乘以2
double sum=0;
if(top==1)
return dis(list[stack[0]],list[stack[top]]);
for(int i=1;i<=top;i++)
{
sum+=dis(list[stack[i-1]],list[stack[i]]);
}
sum+=dis(list[stack[0]],list[stack[top]]);
return sum;
}
int main()
{
int n;
while(scanf("%d",&n),n)
{
init(n);
graham(n);
printf("%.2lf\n",sumlen());
}
return 0;
}