![](https://images2017.cnblogs.com/blog/1123683/201711/1123683-20171109114515075-1442672466.png)
![](https://images2017.cnblogs.com/blog/1123683/201711/1123683-20171110115752544-163346847.png)
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <queue>
#include <cstring>
#define lowbit(x) (x&(-x))
using namespace std;
typedef long long ll;
typedef double db;
const ll eps=1e-8,N=200010;
ll n,m,x,y,z,a[N],sz=0,head[N],F=0,f[N],fa[N];
char opt[6];
ll read(){
ll x=0,f=1;char ch=getchar();
for (;ch<'0'||ch>'9';ch=getchar()) if (ch=='-') f=-1;
for (;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
return x*f;
}
bool dbcmp(db x){
return x<-eps?-1:x>eps?1:0;
}
struct Mat{
ll s[2][2];
ll* operator [](ll x){
return s[x];
}
friend Mat operator *(Mat a,Mat b){
Mat s={0,0,0,0};
for (ll i=0;i<2;i++)
for (ll j=0;j<2;j++)
for (ll k=0;k<2;k++)
s[i][j]+=a[i][k]*b[k][j];
return s;
}
};
struct Graph{
struct E{
ll next,fa,to,w;
friend bool operator <(E a,E b){
return a.w<b.w;
}
}e[N];
void insert(ll a,ll b,ll w){
sz++;
e[sz].next=head[a];
head[a]=sz;
e[sz].fa=a;
e[sz].to=b;
e[sz].w=w;
}
ll find(ll x){
if (x==fa[x]) return x;
return fa[x]=find(fa[x]);
}
void dijkstra(ll x){
memset(f,0x7f,sizeof(f));
typedef pair<ll,ll> P;
priority_queue<P,vector<P>,greater<P> > que;
que.push(P(0,x));f[x]=0;
while(!que.empty()){
ll x=que.top().second;que.pop();
for (ll i=head[x];i;i=e[i].next){
if (f[e[i].to]>f[x]+e[i].w){
f[e[i].to]=f[x]+e[i].w;
que.push(P(f[e[i].to],e[i].to));
}
}
}
}
ll kruskal(){
ll s=0;
for (ll i=1;i<=n;i++) fa[i]=i;
sort(e+1,e+sz+1);
for (ll i=1;i<=sz;i++){
ll a=find(e[i].fa),b=find(e[i].to);
if (a!=b){
fa[a]=b;
s+=e[i].w;
}
}
return s;
}
};
struct FTree{
ll t[N];
void add(ll x,ll v){
for (ll i=x;i<=n;i+=lowbit(i)) t[i]+=v;
}
ll query(ll x){
ll s=0;
for (ll i=x;i>=1;i-=lowbit(i)) s+=t[i];
return s;
}
};
struct SumSTree{
struct P{
ll l,r,v,tag;
}t[4*N];
ll build(ll x,ll l,ll r){
t[x].l=l,t[x].r=r,t[x].tag=0;
if (l==r) return t[x].v=a[l];
ll mid=(l+r)/2;
return t[x].v=build(x*2,l,mid)+build(x*2+1,mid+1,r);
}
void pushdown(ll x){
if (!t[x].tag) return;
t[x*2].v+=(t[x*2].r-t[x*2].l+1)*t[x].tag;
t[x*2+1].v+=(t[x*2+1].r-t[x*2+1].l+1)*t[x].tag;
t[x*2].tag+=t[x].tag;
t[x*2+1].tag+=t[x].tag;
t[x].tag=0;
}
void add(ll x,ll l,ll r,ll v){
t[x].v+=(r-l+1)*v;
if (l==t[x].l&&r==t[x].r){t[x].tag+=v;return;}
pushdown(x);
ll mid=(t[x].l+t[x].r)/2;
if (r<=mid) add(x*2,l,r,v);
else if (l>=mid+1) add(x*2+1,l,r,v);
else add(x*2,l,mid,v),add(x*2+1,mid+1,r,v);
}
ll query(ll x,ll l,ll r){
if (l==t[x].l&&r==t[x].r) return t[x].v;
pushdown(x);
ll mid=(t[x].l+t[x].r)/2;
if (r<=mid) return query(x*2,l,r);
else if (l>=mid+1) return query(x*2+1,l,r);
else return query(x*2,l,mid)+query(x*2+1,mid+1,r);
}
};
struct MaxSTree{
struct P{
ll l,r,v,tag;
}t[4*N];
ll build(ll x,ll l,ll r){
t[x].l=l,t[x].r=r,t[x].tag=0;
if (l==r) return t[x].v=a[l];
ll mid=(l+r)/2;
return t[x].v=max(build(x*2,l,mid),build(x*2+1,mid+1,r));
}
void pushdown(ll x){
if (!t[x].tag) return;
t[x*2].v+=t[x].tag;
t[x*2+1].v+=t[x].tag;
t[x*2].tag+=t[x].tag;
t[x*2+1].tag+=t[x].tag;
t[x].tag=0;
}
ll add(ll x,ll l,ll r,ll v){
if (l==t[x].l&&r==t[x].r){t[x].tag+=v;return t[x].v+=v;}
pushdown(x);
ll mid=(t[x].l+t[x].r)/2;
if (r<=mid) return t[x].v=max(t[x*2+1].v,add(x*2,l,r,v));
else if (l>=mid+1) return t[x].v=max(t[x*2].v,add(x*2+1,l,r,v));
else return t[x].v=max(add(x*2,l,mid,v),add(x*2+1,mid+1,r,v));
}
ll query(ll x,ll l,ll r){
if (l==t[x].l&&r==t[x].r) return t[x].v;
pushdown(x);
ll mid=(t[x].l+t[x].r)/2;
if (r<=mid) return query(x*2,l,r);
else if (l>=mid+1) return query(x*2+1,l,r);
else return max(query(x*2,l,mid),query(x*2+1,mid+1,r));
}
};
struct KDTree{
struct P{
ll d[2],mx[2],mn[2],v,l,r,sum;
ll& operator [](ll x){
return d[x];
}
friend bool operator <(P a,P b){
return a[F]<b[F];
}
}t[N];
void update(ll x){
ll l=t[x].l,r=t[x].r;
for (ll i=0;i<2;i++){
t[x].mn[i]=t[x].mx[i]=t[x][i];
if (l) t[x].mn[i]=min(t[x].mn[i],t[l].mn[i]),t[x].mx[i]=max(t[x].mx[i],t[l].mx[i]);
if (r) t[x].mn[i]=min(t[x].mn[i],t[r].mn[i]),t[x].mx[i]=max(t[x].mx[i],t[r].mx[i]);
}
t[x].sum=t[x].v+t[l].sum+t[r].sum;
}
ll build(ll l,ll r){
ll mid=(l+r)/2;
nth_element(t+l,t+mid,t+r+1);
F=!F;
if (l<mid) t[mid].l=build(l,mid-1);
if (r>mid) t[mid].r=build(mid+1,r);
update(mid);
return mid;
}
};
int main(){
}
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
typedef double db;
const int N=10010;
int n;
struct P{
db x,y;
}p[N],sta[N];
db direct(P a,P b,P c){//cbbc aaaa xyxy l<0 r>0
return (c.x-a.x)*(b.y-a.y)-(b.x-a.x)*(c.y-a.y);
}
bool cmp(P a,P b){//a<b l:b
return direct(p[1],a,b)<0;
}
db graham(){
db s=0;int k=1,top=2;
for (int i=1;i<=n;i++) if ((p[i].y>p[k].y)||(p[i].y==p[k].y&&p[i].x<p[k].x)) k=i;
swap(p[1],p[k]);
sort(p+2,p+n+1,cmp);
sta[1]=p[1],sta[2]=p[2];
for (int i=3;i<=n;i++){
while(top>=2&&direct(sta[top-1],sta[top],p[i])>0) top--;
sta[++top]=p[i];
}
sta[++top]=p[1];
for (int i=1;i<top;i++) s+=hypot(sta[i].x-sta[i+1].x,sta[i].y-sta[i+1].y);
return s;
}
bool intersect(P a1,P a2,P b1,P b2){
return
min(a1.x,a2.x)<=max(b1.x,b2.x)&&
min(b1.x,b2.x)<=max(a1.x,a2.x)&&
min(a1.y,a2.y)<=max(b1.y,b2.y)&&
min(b1.y,b2.y)<=max(a1.y,a2.y)&&
direct(a1,a2,b1)*direct(a1,a2,b2)<=0&&
direct(b1,b2,a1)*direct(b1,b2,a2)<=0;
}
int main(){
scanf("%d",&n);
for (int i=1;i<=n;i++) scanf("%lf %lf",&p[i].x,&p[i].y);
printf("%.2lf",graham());
}