//点结构体
typedef struct
{
int x,y;
}Point;
//左下角点Po
Point leftBotm;
//极角比较函数
int leftTurn(Point p1,Point p2,Point p3) //p1:next-top, p2:top(), p3:pi
{
int ret=(p3.x-p1.x)*(p2.y-p1.y)-(p2.x-p1.x)*(p3.y-p1.y);
if(ret<0)
{
return -1; //左转
}
else if(ret==0)
{
return 0; // 共线
}
else
{
return 1; //右转
}
}
//仿比较函数结构体
struct compare
{
bool operator()(const Point &p,const Point &q)
{
int ret=leftTurn(leftBotm,p,q);
if(ret==-1)
{
return false;
}
else if(ret==1)
{
return true;
}
else
{
int minus=(p.x-leftBotm.x)*(p.x-leftBotm.x)-(q.x-leftBotm.x)*(q.x-leftBotm.x);
if(minus<0)
{
return false;
}
else
{
return true;
}
}
}
};
//最小堆
typedef priority_queue<Point,vector<Point>,compare> minHeap;
int main()
{
minHeap heap;
int n;
Point input;
vector<Point> final;
cin>>n;
int x,y,k;
cin>>input.x>>input.y;
final.push_back(input);
x=input.x;
y=input.y;
k=0;
for(int i=1;i<n;++i)
{
cin>>input.x>>input.y;
final.push_back(input);
if(input.x<=x&&input.y<=y)
{
x=input.x;
y=input.y;
k=i;
}
}
leftBotm.x=x;
leftBotm.y=y;
for(int i=0;i<n;++i)
{
if(i!=k)
{
heap.push(final[i]);
}
}
Point pre,now;
pre=heap.top();
heap.pop();
final.clear();
while(!heap.empty())
{
now=heap.top();
heap.pop();
if(leftTurn(leftBotm,pre,now)==0)
{
pre=now;
}
else
{
final.push_back(pre);
pre=now;
}
}
final.push_back(pre);
/*
全部已经按极角整理完毕,重复角只保留距离最远的
*/
stack<Point> s;
s.push(leftBotm);
s.push(final[0]);
s.push(final[1]);
for(int j=2;j<(int)final.size();++j)
{
while(leftTurn(s._Get_container()[s.size()-2],s._Get_container()[s.size()-1],final[j])!=-1)
{
s.pop();
}
s.push(final[j]);
}
cout<<endl;
for(int k=0;k<(int)s.size();++k)
{
cout<<s._Get_container()[k].x<<","<<s._Get_container()[k].y<<endl;
}
return 0;
}