#include <bits/stdc++.h>
using namespace std;
bool debug = 0;
int n, m, k;
int dx[4] = {0, 1, 0, -1}, dy[4] = {1, 0, -1, 0};
string direc = "RDLU";
long long ln, lk, lm;
void etp(bool f = 0) {
  puts(f ? "Yes" : "No");
  exit(0);
}
void addmod(int &x, int y, int mod = 1000000007) {
  x += y;
  if (x >= mod) x -= mod;
}
void et() {
  puts("-1");
  exit(0);
}
long long fastPow(long long x, long long y, int mod = 1000000007) {
  long long ans = 1;
  while (y > 0) {
    if (y & 1) ans = (x * ans) % mod;
    x = x * x % mod;
    y >>= 1;
  }
  return ans;
}
struct Point {
  int x, y;
  Point() {}
  Point(int x, int y) : x(x), y(y) {}
  long double abs() const { return hypot(x, y); }
  long double arg() const { return atan2(y, x); }
  Point operator*(double o) const { return Point(x * o, y * o); }
  Point operator+(const Point &o) const { return Point(x + o.x, y + o.y); }
  Point operator-(const Point &o) const { return Point(x - o.x, y - o.y); }
  bool operator<(const Point &o) const {
    return x < o.x - 1e-18 || (x < o.x + 1e-18 && y < o.y - 1e-18);
  }
  Point scale(double o) const { return *this * (o / abs()); }
  Point rotY() const { return Point(-y, x); }
  Point rotX() const { return Point(y, -x); }
  int cross(Point b) const { return x * b.y - b.x * y; }
  int dot(Point b) const { return x * b.x + y * b.y; }
  long double disToSeg(Point &a, Point &b) {
    return fabs(((*this) - a).cross(b - a) / (b - a).abs());
  }
  void readin() { scanf("%d%d", &x, &y); }
  void pp() { printf("%d %d\n", x, y); }
};
char s[505][505];
bool hs(int i, int j, char num) {
  return s[i][j] == num || s[i + 1][j] == num || s[i][j + 1] == num ||
         s[i + 1][j + 1] == num;
}
vector<Point> convex(vector<Point> &vp) {
  sort(vp.begin(), vp.end());
  vector<Point> ans1, ans2;
  for (int(i) = 0; (i) < (int)(vp.size()); (i)++) {
    while (ans1.size() > 1) {
      Point o = ans1[ans1.size() - 2], a = ans1.back();
      if ((a - o).cross(vp[i] - o) <= 0) {
        ans1.pop_back();
      } else
        break;
    }
    ans1.push_back(vp[i]);
  }
  for (int i = vp.size() - 1; i >= 0; i--) {
    while (ans2.size() > 1) {
      Point o = ans2[ans2.size() - 2], a = ans2.back();
      if ((a - o).cross(vp[i] - o) <= 0) {
        ans2.pop_back();
      } else
        break;
    }
    ans2.push_back(vp[i]);
  }
  for (int i = 1; i < ans2.size() - 1; i++) ans1.push_back(ans2[i]);
  return ans1;
}
void fmain() {
  while (scanf("%d", &n), n) {
    vector<Point> vp;
    for (int(i) = 1; (i) <= (int)(n); (i)++) scanf("%s", s[n + 1 - i] + 1);
    for (int(i) = 1; (i) <= (int)(n - 1); (i)++)
      for (int(j) = 1; (j) <= (int)(n - 1); (j)++) {
        if (hs(i, j, '0')) continue;
        if (!hs(i, j, '1')) continue;
        vp.push_back(Point(j, i));
      }
    vector<Point> ans = convex(vp);
    printf("%d\n", ans.size());
    ans[0].pp();
    for (int i = ans.size() - 1; i >= 1; i--) ans[i].pp();
  }
}
int main() {
  fmain();
  return 0;
}
