#include <bits/stdc++.h>
using namespace std;

const double EPS = 1e-8;
const double INF = 1e12;

//point
typedef complex<double> P;
namespace std {
	bool operator < (const P& a, const P& b) {
		return real(a) != real(b) ? real(a) < real(b) : imag(a) < imag(b);
	}
	bool cmp_y(const P &a, const P &b){
		return a.imag() != b.imag() ? a.imag() < b.imag() : a.real() < b.real();
	}
}
double cross(const P& a, const P& b) {
	return imag(conj(a)*b);
}
double dot(const P& a, const P& b) {
	return real(conj(a)*b);
}
int ccw(P a, P b, P c) {
  b -= a; c -= a;
  if (cross(b, c) > 0)   return +1;       // counter clockwise
  if (cross(b, c) < 0)   return -1;       // clockwise
  if (dot(b, c) < 0)     return +2;       // c--a--b on line
  if (norm(b) < norm(c)) return -2;       // a--b--c on line
  return 0;								  // a--c--b on line
}

// line
struct L : public vector<P> {
	L(const P& a, const P& b) {
		push_back(a); push_back(b);
	}
};

// polygon
typedef vector<P> G;

P extreme(const vector<P> &po, const L &l) {
  int k = 0;
  for (int i = 1; i < po.size(); ++i)
    if (dot(po[i], l[1]-l[0]) > dot(po[k], l[1]-l[0])) k = i;
  return po[k];
}

enum { OUT, ON, IN };
int contains(const G& po, const P& p) {
  bool in = false;
  for (int i = 0; i < po.size(); ++i) {
  	P a = po[i] - p, b = po[(i+1)%po.size()] - p;
    if (imag(a) > imag(b)) swap(a, b);
    if (imag(a) <= 0 && 0 < imag(b))
      if (cross(a, b) < 0) in = !in;
    if (cross(a, b) == 0 && dot(a, b) <= 0) return ON;
  }
  return in ? IN : OUT;
}

double area2(const G& po) {
	double A = 0;
  	for (int i = 0; i < po.size(); ++i) 
    	A += cross(po[i], po[(i+1)%po.size()]);
	//????????????????????????????????¨????????????
  	return A/2;
}

bool isconvex(const G &p) {
	int n = p.size();
	if(cross(p[0]-p[n-1],p[n-2]-p[n-1]) < 0) return false;
	for(int i = 1; i < n-1; ++i) {
		if(cross(p[i+1]-p[i],p[i-1]-p[i]) < 0) return false;
	}
	return true;

}

G convex_hull(G ps) {
  int n = ps.size(), k = 0;
  sort(ps.begin(), ps.end(), cmp_y);
  G r(2*n);
  for(int i = 0; i < n; i++){
    while(k>1 && cross(r[k-1]-r[k-2],ps[i]-r[k-2]) < -EPS)k--;
    r[k++] = ps[i];
  }
  for(int i = n-2, t = k; i >= 0; i--){
    while(k>t && cross(r[k-1]-r[k-2],ps[i]-r[k-2]) < -EPS)k--;
    r[k++] = ps[i];
  }
  r.resize(k-1);
  return r;
}
	
int main() {
	int n;
	cin >> n;
	G po;
	for(int i=0; i<n; ++i) {
		double x, y;
		cin >> x >> y;
		P p(x, y);
		po.push_back(p);
	}
	G ans = convex_hull(po);
	cout << ans.size() << endl;
	for(int i=0; i<ans.size(); ++i) {
		cout << ans[i].real() << " " << ans[i].imag() << endl;
	}
}