// http://infoarena.ro/problema/infasuratoare
#include <fstream>
#include <iomanip>
#include <cmath>
#include <algorithm>
#include <vector>
using namespace std;
#define x first
#define y second
ifstream in("infasuratoare.in");
ofstream out("infasuratoare.out");
const int MAXSIZE = 120001;
const int oo = 0x3f3f3f3f;
int nrPoints,selectedPoints;
bool onConvexHull[MAXSIZE];
int previousPointOnConvexHull[MAXSIZE];
pair<double,double> minPoint = make_pair(oo,oo);
vector< pair<double,double> > points;
//double dist(pair<double,double> one,pair<double,double> two);
bool leftTurn(pair<double,double> one,pair<double,double> two,pair<double,double> three);
double determinant(pair<double,double> one,pair<double,double> two,pair<double,double> three);
class compare {
public:
bool operator() (pair<double,double> one,pair<double,double> two) {
//double oneAtan = atan2(one.y - minPoint.y,one.x - minPoint.x);
//double twoAtan = atan2(two.y - minPoint.y,two.x - minPoint.x);
//if(oneAtan != twoAtan)
return (atan2(one.y - minPoint.y,one.x - minPoint.x) < atan2(two.y - minPoint.y,two.x - minPoint.x));
//else
//return (dist(minPoint,one) < dist(minPoint,two));
}
};
int main() {
in >> nrPoints;
points.reserve(nrPoints);
pair<double,double> point;
for(int i=1;i<=nrPoints;i++) {
in >> point.x >> point.y;
minPoint = min(minPoint,point);
points.push_back(point);
}
//out << "Initial point: " << minPoint.x << " " << minPoint.y << "\n";
sort(points.begin(),points.end(),compare());
selectedPoints = 2;
int previous = find(points.begin(),points.end(),minPoint) - points.begin(); // indicele lui minPoint
int current = 0;
if(current < previous)
swap(current,previous);
onConvexHull[previous] = onConvexHull[current] = true;
previousPointOnConvexHull[current] = previous;
for(int i=1;i<nrPoints;i++) {
// daca este o intoarcere la dreapta
while(!leftTurn(points[previous],points[current],points[i]) && selectedPoints > 2) {
// nodul curent il scot din infasuratoarea convexa
onConvexHull[current] = false;
current = previous;
previous = previousPointOnConvexHull[previous];
selectedPoints--;
}
onConvexHull[i] = true;
previous = current;
current = i;
previousPointOnConvexHull[current] = previous;
selectedPoints++;
}
/*for(unsigned int i=0;i<points.size();i++)
out << points[i].x << " " << points[i].y << "\n";
out << "\n\n";*/
//out << "Convex hull:\n";
out << selectedPoints << fixed << setprecision(6) << "\n";
for(int i=0;i<nrPoints;i++)
if(onConvexHull[i])
out << points[i].x << " " << points[i].y << "\n";
out << minPoint.x << " " << minPoint.y << "\n";
return (0);
}
/*double dist(pair<double,double> one,pair<double,double> two) {
return (sqrt(pow(one.x - two.x,2) + pow(one.y - two.y,2)));
}*/
bool leftTurn(pair<double,double> one,pair<double,double> two,pair<double,double> three) {
return (determinant(one,two,three) > 0);
}
double determinant(pair<double,double> one,pair<double,double> two,pair<double,double> three) {
return (one.x * two.y + three.x * one.y + two.x * three.y
- three.x * two.y - one.x * three.y - two.x * one.y);
}