/*
函数版本:0.4
*/
#include<iostream>
#include<stdio.h>
#include<math.h>
#include<vector>
#include<algorithm>
using namespace std;
#define EPS (1e-15)
#define equals(a,b) (fabs((a)-(b))<EPS)
#define COUNTER_CLOCKWISE 1
#define CLOCKWISE -1
#define ONLINE_BACK 2
#define ONLINE_FRONT -2
#define ON_SEGMENT 0


struct Segment;
class Point;
typedef Point Vector;
typedef Segment Line;
typedef vector<Point> Polygon;

class Point {
public:
	double x, y;
	Point() {}
	Point(double xx, double yy) {
		x = xx;
		y = yy;
	}
	Point operator + (const Point& p) { return Point(x + p.x, y + p.y); }
	Point operator - (const Point& p) { return Point(x - p.x, y - p.y); }
	Point operator * (const double k) { return Point(x * k, y * k); }
	Point operator / (const double k) { return Point(x / k, y / k); }

	double norm() { return x * x + y * y; }
	double abs() { return sqrt(norm()); }
	double dot(Point p) { return x * p.x + y * p.y; }
	double cross(Point& p) { return x * p.y - y * p.x; }
	double distance(Point& p) { return (*this - p).abs(); }

	bool operator == (const Point& p) const {
		return fabs(x - p.x) < EPS && fabs(y - p.y) < EPS;
	}
	//version1
	/*bool operator < (const Point& p) const {
		return x - p.x < -EPS || (fabs(x - p.x) < EPS && y - p.y < -EPS);
	}*/

	//version2
	bool operator < (const Point& p) const {
		return y - p.y < -EPS || (fabs(y - p.y) < EPS && x - p.x < -EPS);
	}

	void input() {
		cin >> x >> y;
	}
};

class Segment {
public:
	Point p1, p2;
	void input() {
		p1.input();
		p2.input();
	}
};

class Circle {
public:
	Point c;
	double r;
	void input() {
		c.input();
		cin >> r;
	}
};


double distance(Point p, Line s) {
	Vector a = s.p2 - s.p1;
	Vector b = p - s.p1;
	return a.cross(b) / a.abs();
}

double distanceS(Point p, Segment s) {
	Vector p1p = p - s.p1;
	Vector p2p = p - s.p2;
	Vector p1p2 = s.p2 - s.p1;
	Vector p2p1 = s.p1 - s.p2;
	if (p1p.dot(p1p2) < 0) {
		return p1p.abs();
	}
	else if (p2p.dot(p2p1) < 0) {
		return p2p.abs();
	}
	else {
		return distance(p, s);
	}
}

Point project(Point p, Segment s) {
	Vector hepo = p - s.p1;
	Vector base = s.p2 - s.p1;
	Vector t = base * (hepo.dot(base) / base.norm());
	return s.p1 + t;
}

int ccw(Point p0, Point p1, Point p) {
	Vector p0p1 = p1 - p0;
	Vector p0p;
	p0p = p - p0;
	if (p0p1.cross(p0p) > EPS) {
		return COUNTER_CLOCKWISE;
	}
	else if (p0p1.cross(p0p) < -EPS) {
		return CLOCKWISE;
	}
	else if (p0p1.dot(p0p) < -EPS) {
		return ONLINE_BACK;
	}
	else if (p0p1.norm() < p0p.norm()) {
		return ONLINE_FRONT;
	}
	else {
		return ON_SEGMENT;
	}
}

bool intersection(Segment s1, Segment s2) {
	Point p0 = s1.p1;
	Point p1 = s1.p2;
	Point p2 = s2.p1;
	Point p3 = s2.p2;
	return ccw(p0, p1, p2) * ccw(p0, p1, p3) <= 0 &&
		ccw(p2, p3, p0) * ccw(p2, p3, p1) <= 0;
}
Point getCrossPoint(Segment s1, Segment s2) {
	Point p1 = s1.p1;
	Point p2 = s1.p2;
	Point p3 = s2.p1;
	Point p4 = s2.p2;
	Vector p1_p2 = p2 - p1;
	Vector p1_p3 = p3 - p1;
	Vector p1_p4 = p4 - p1;
	Vector p4_p3 = p3 - p4;
	double d1 = fabs(p1_p2.cross(p1_p4)) / p1_p2.abs();
	double d2 = fabs(p1_p2.cross(p1_p3)) / p1_p2.abs();
	double r = d1 / (d1 + d2);
	Vector p4_p = p4_p3 * r;
	Point p = p4 + p4_p;
	return p;
}
pair<Point, Point> getCrossPoints(Circle circle, Line s) {
	Point p, p1, p2;
	Vector base, offset;
	double dis, d;
	p = project(circle.c, s);
	dis = distance(circle.c, s);
	base = s.p2 - s.p1;
	d = sqrt(circle.r * circle.r - dis * dis);
	offset = base / base.abs() * d;
	p1 = p + offset;
	p2 = p - offset;
	if (p1 < p2) {
		return make_pair(p1, p2);
	}
	else {
		return make_pair(p2, p1);
	}
}
Vector getOrthogonalUnitVector(Vector v) {
	double abs = v.abs();
	Vector unit;
	return Vector(-v.y / abs, v.x / abs);
}
pair<Point, Point> getCrossPoints(Circle c1, Circle c2) {
	Vector c1_c2 = c2.c - c1.c;
	Vector orth = getOrthogonalUnitVector(c1_c2);

	double l = c1_c2.abs(), r1 = c1.r, r2 = c2.r;
	double x = (l * l - r2 * r2 + r1 * r1) / (2 * l);
	double d = sqrt(r1 * r1 - x * x);
	Point p1 = c1.c + c1_c2 * (x / l) + orth * d;
	Point p2 = c1.c + c1_c2 * (x / l) - orth * d;
	if (p1 < p2) {
		return make_pair(p1, p2);
	}
	else {
		return make_pair(p2, p1);
	}
}
int contains(Polygon g, Point p) {
	int n = g.size();
	bool x = false;
	Point a, b, t;
	for (int i = 0; i < n; i++) {
		a = g[i] - p, b = g[(i + 1) % n] - p;
		if (fabs(a.cross(b)) < EPS && a.dot(b) < EPS) {
			return 1;
		}
		if (a.y > b.y) {
			t = a;
			a = b;
			b = t;
		}
		if (a.y < EPS && EPS < b.y && a.cross(b)>EPS) {
			x = !x;
		}
	}
	return (x ? 2 : 0);
}
Polygon andrewScan(Polygon s) {
	Polygon u, l;
	if (s.size() < 3) {
		return s;
	}
	sort(s.begin(), s.end());
	u.push_back(s[0]);
	u.push_back(s[1]);
	l.push_back(s[s.size() - 1]);
	l.push_back(s[s.size() - 2]);

	for (int i = 2; i < s.size(); i++) {
		for (int n = u.size(); n >= 2 && ccw(u[n - 2], u[n - 1], s[i]) >= 0 ; n--) {
			u.pop_back();
		}
		u.push_back(s[i]);
	}

	for (int i = s.size()-3; i >=0; i--) {
		for (int n = l.size(); n >= 2 && ccw(l[n - 2], l[n - 1], s[i]) >=0; n--) {
			l.pop_back();
		}
		l.push_back(s[i]);
	}
	reverse(l.begin(), l.end());
	for (int i = u.size() - 2; i >= 1; i--) {
		l.push_back(u[i]);
	}
	return l;
}
int main() {
	Polygon poly;
	int n, i, q;
	cin >> n;
	for (i = 0; i < n; i++) {
		Point p;
		cin >> p.x >> p.y;
		poly.push_back(p);
	}
	Polygon hull = andrewScan(poly);
	cout << hull.size() << endl;
	for (int i = 0; i < hull.size(); i++) {
		printf("%.0lf %.0lf\n", hull[i].x, hull[i].y);
	}
}


Measured memory_bytes: 10412