1 #include <cmath>
2 #include <cstdio>
3 #include <cstdlib>
4 #include <iostream>
5
6 using namespace std;
7
8 const int N = 105;
9
10 struct point {
11 long long x, y;
12 }p[N];
13
14 long long dis(point A, point B) {//两点距离
15 return (long long)sqrt((A.x - B.x) * (A.x - B.x) + (A.y - B.y) * (A.y - B.y));
16 }
17
18 long long crossProd(point A, point B, point C) {//叉乘
19 return (B.x - A.x) * (C.y - A.y) - (B.y - A.y) * (C.x - A.x);
20 }
21
22 int cmp1(const void *a, const void *b) {
23 point *c = (point *)a;
24 point *d = (point *)b;
25 long long k = crossProd(p[0], *c, *d);
26 if (k < 0 || (!k && dis(p[0], *c) > dis(p[0], *d))) return 1;
27 return -1;
28 }
29
30 int cmp2(const void *a, const void *b) {
31 point *c = (point *)a;
32 point *d = (point *)b;
33 if (c->x != d->x) return (int)(c->x - d->x);
34 return (int)(c->y - d->y);
35 }
36
37 int Graham(point p[], int n) {//求凸包,返回凸包顶点个数
38 long long x = p[0].x;
39 long long y = p[0].y;
40 int mi = 0;
41 for (int i=1; i<n; ++i) {
42 if (p[i].y < y || (p[i].y == y && p[i].x < x)) {
43 x = p[i].x;
44 y = p[i].y;
45 mi = i;
46 }
47 }
48 point tmp = p[0];
49 p[0] = p[mi];
50 p[mi] = tmp;
51 qsort(p+1, n-1, sizeof(point), cmp1);
52 int top = 1;
53 for (int i=2; i<n; ++i) {
54 while (crossProd(p[top-1], p[top], p[i]) <= 0 && top >= 1) --top;
55 p[++top] = p[i];
56 }
57 return top + 1;
58 }
59
60 void solve(point p[], int n) {
61 int top = Graham(p, n);
62 qsort(p, top, sizeof(point), cmp2);
63 for (int i=0; i<top; ++i) printf ("%lld %lld\n", p[i].x, p[i].y);
64 }
65
66 int main() {
67 int t;
68 scanf ("%d", &t);
69 while (t--) {
70 int n;
71 scanf ("%d", &n);
72 for (int i=0; i<n; ++i) scanf ("%lld%lld", &p[i].x, &p[i].y);
73 solve(p, n);
74 }
75 return 0;
76 }