#include <bits/stdc++.h>
using namespace std;
#define mem(x) memset(x,0,sizeof(x))
#define ll long long 
typedef long long LL;
inline int rint() { int a; scanf("%d", &a); return a; }
inline long long rll() { long long a; scanf("%lld", &a); return a; }
//节点从0到n-1
#define maxn 100006
struct node { double x, y; };
int n;//有多少个点
int tot;//凸包上的点
node p[maxn];//所有点数组从0开始
node P[maxn];//凸包上的点
const double pi = acos(-1.0);
const double eps = 1e-9;
//三点差积	 
double X(node A, node B, node C) { return (B.x - A.x)*(C.y - A.y) - (C.x - A.x)*(B.y - A.y); }
//三点点积	 
double dian(node A, node B, node C) { return (B.x - A.x)*(C.x - A.x) + (C.y - A.y)*(B.y - A.y); }
//两点距离
double len(node A, node B) { return sqrt((A.x - B.x)*(A.x - B.x) + (A.y - B.y)*(A.y - B.y)); }
//角度小的在前面,相同的话距离小的在前面
bool cmp(node A, node B) {
	double pp = X(p[0], A, B);
	if (pp > 0)return true;
	if (pp < 0)return false;
	if (pp == 0)return len(p[0], A) < len(p[0], B);
}
//建立凸包存到P里//以下是n>=3的情况,n=1,2要特判
void build() {
	//找左下角的点
	for (int i = 0; i < n; i++) {
		if (p[i].y < p[0].y) swap(p[i], p[0]);
		if (p[i].y == p[0].y&&p[i].x < p[0].x) swap(p[i], p[0]);
	}
	sort(p + 1, p + n, cmp);
	P[0] = p[0];
	P[1] = p[1];
	tot = 1;//初始两个点
	for (int i = 2; i < n; i++) {
		//不需要边上的点//while (tot > 0 && X(P[tot - 1], P[tot], p[i]) <= 0)tot--;
		//需要边上的点
		while (tot > 0 && X(P[tot - 1], P[tot], p[i]) < 0)tot--;
		tot++;
		P[tot] = p[i];
	}

	node endd = P[tot];
	for (int i = n - 1; i >= 0; i--) {
		if (abs(X(P[0], endd, p[i])) <= eps) {
			if (dian(p[i], P[0], endd) < 0) {
				tot++;
				P[tot] = p[i];
			}
		}
		else break;
	}
	tot++;
}
int main() {
	//freopen("input.txt", "r", stdin);
	//freopen("output.txt", "w", stdout);
	ios::sync_with_stdio(false);
	n = rint();
	for (int i = 0; i < n; i++) scanf("%lf %lf", &p[i].x, &p[i].y);
	build();
	cout << tot << endl;
	for (int i = 0; i < tot; i++) cout << P[i].x << " " << P[i].y << endl;
	return 0;
}
