#if 0
はじめ、一番左の一番下の点を始点として凸包を求めたがWAしてしまった。問題文をよく読むと一番下の一番左の点を始点にしなければならないと分かったので、最初に行う点のソートの際にy座標を優先し、それに合わせて複素数平面の座標を設定することで、一番下の一番左の点から凸包を求めることができ、無事解くことができた。
#endif

#include <bits/stdc++.h>
using namespace std;
typedef long long int ll;
typedef complex<double> xy_t;
const double EPS = 1e-11;

double dot_product(xy_t a, xy_t b) {
  return (conj(a)*b).real();
}
double cross_product(xy_t a, xy_t b) {
  return (conj(a)*b).imag();
}
xy_t projection(xy_t p, xy_t b) {
  return b*dot_product(p,b)/norm(b);
}

int N;
pair<int,int> P[100010];
xy_t PL[100010], PH[100010];

int main() {
  cin >> N;
  int x, y;
  for (int i = 0; i < N; i++) {
    cin >> x >> y;
    P[i] = make_pair(y,x);
  }
  sort(P, P+N);
  for (int i = 0; i < N; i++) {
    PL[i] = xy_t(P[i].second*1.0, P[i].first*1.0);
    PH[i] = xy_t(P[N-1-i].second*1.0, P[N-1-i].first*1.0);
  }
  vector<xy_t> VL;
  VL.push_back(PL[0]); VL.push_back(PL[1]);
  for (int i = 2; i < N; i++) {
    bool c = true;
    xy_t p2 = PL[i];
    while (c) {
      if (VL.size() <= 1) {
        VL.push_back(p2);
        c = false;
      } else {
        xy_t p1 = VL[VL.size()-1], p0 = VL[VL.size()-2];
        if (cross_product(p1-p0, p2-p1) > 0.0 || abs(cross_product(p1-p0, p2-p1)) < EPS) {
          c = false; VL.push_back(p2);
        }
        else
          VL.pop_back();
      }
    }
  }
  vector<xy_t> VH;
  VH.push_back(PH[0]); VH.push_back(PH[1]);
  for (int i = 2; i < N; i++) {
    bool c = true;
    xy_t p2 = PH[i];
    while (c) {
      if (VH.size() <= 1) {
        VH.push_back(p2);
        c = false;
      } else {
        xy_t p1 = VH[VH.size()-1], p0 = VH[VH.size()-2];
        if (cross_product(p1-p0, p2-p1) > 0.0 || abs(cross_product(p1-p0, p2-p1)) < EPS) {
          c = false; VH.push_back(p2);
        }
        else
          VH.pop_back();
      }
    }
  }
  cout << VL.size() + VH.size() - 2 << endl;
  for (int i = 0; i < VL.size(); i++)
    cout << (int)(VL[i].real()) << ' ' << (int)(VL[i].imag()) << endl;
  for (int i = 1; i < VH.size()-1; i++)
    cout << (int)(VH[i].real()) << ' ' << (int)(VH[i].imag()) << endl;
}

