Problem p02300 (C++) — buggy submission, verdict: Time Limit Exceeded

#include <cmath>
#include <iomanip>
#include <iostream>
#include <math.h>
#include <queue>
#include <stack>

using namespace std;

//-------------------------------------------------------------------------------------
/*2点[(x1,y1),(x2,y2)]を入力し二点を通る直線ax+by+cの(a,b,c)を返す,  */
/*x1==x2ならfalseを返す*/
/*falseならばx=cの形の直線*/
void straight_line_passing_through_the_two_points(double x1, double y1,
                                                  double x2, double y2,
                                                  double *a, double *b,
                                                  double *c) {
  *a = (y2 - y1);
  *b = -(x2 - x1);
  *c = y2 * (x2 - x1) - x2 * (y2 - y1);
}

//-------------------------------------------------------------------------------------
/*(x,y)を通るa1x+b1y+c1=0に垂直な直線a2x+b2y+c2=0を返す*/
bool vertical_straight_line(double x, double y, double a1, double b1, double c1,
                            double *a2, double *b2, double *c2) {
  if (a1 * x + b1 * y + c1 == 0)
    return false;
  *a2 = -b1;
  *b2 = a1;
  *c2 = b1 * x - a1 * y;
  return true;
}

//-------------------------------------------------------------------------------------
/*2直線 a1x+b1y+c1=0 a2x+b2y+c2=0 の交点 (x,y)を返す*/
/*2直線が平行であるならば0を返す*/
int intersection_and_parallel(double a1, double b1, double c1, double a2,
                              double b2, double c2, double *x, double *y) {
  if (a1 * b2 == a2 * b1)
    return false; // 平行の判定

  *x = (b1 * c2 - b2 * c1) / (a1 * b2 - a2 * b1);
  *y = (a2 * c1 - a1 * c2) / (a1 * b2 - a2 * b1);

  return true;
}

//-------------------------------------------------------------------------------------
/*
 a1x+b1y+c1=0 と　a2x+b2y+c2=0 が
 平行なら2
 直交なら1
 それ以外は0
 を返す
 */
int judges_whether_parallel_or_perpendicular(double a1, double b1, double c1,
                                             double a2, double b2, double c2) {
  if (a1 * b2 == a2 * b1)
    return 2;
  if (a1 * a2 + b1 * b2 == 0)
    return 1;
  return 0;
}

//-------------------------------------------------------------------------------------
/*直線ax+by+c=0に対し　(x1,y1)と線対称な位置(x2,y2)を出力*/
/*vertical_straight_lineを使用*/
/*intersection_and_parallelを使用*/
void line_symmetry(double a, double b, double c, double x1, double y1,
                   double *x2, double *y2) {
  // 垂直な直線を求める
  double a2, b2, c2;
  vertical_straight_line(x1, y1, a, b, c, &a2, &b2, &c2);

  // 垂直な直線との交点を求める
  double c_x, c_y;
  intersection_and_parallel(a, b, c, a2, b2, c2, &c_x, &c_y);
  *x2 = x1 + 2 * (c_x - x1);
  *y2 = y1 + 2 * (c_y - y1);
}

//-------------------------------------------------------------------------------------
/*2点(x1,y1), (x2,y2) の距離*/
double distance_between_the_two_pointss(double x1, double y1, double x2,
                                        double y2) {
  return sqrt(fabs((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)));
}

//-------------------------------------------------------------------------------------
/* (x1,y1)から(x2,y2)へ伸ばした直線の角度を求める  */
/*-π　〜　+π　まで*/
double angle_of_the_line(double x1, double y1, double x2, double y2) {
  return atan2(y2 - y1, x2 - x1);
}

//-------------------------------------------------------------------------------------
/*(x1,y1)と(x2,y2)を両端に持つ線分と*/
/*(x3,y3)と(x4,y4)を両端に持つ線分が*/
/*交差するなら1 交差しないなら0を出力する*/
/* straight_line_passing_through_the_two_pointsを使用 */
/* intersection_and_parallelを使用 */
int line_segment_cross_decision(double x1, double y1, double x2, double y2,
                                double x3, double y3, double x4, double y4) {
  double a1, b1, c1, a2, b2, c2;
  straight_line_passing_through_the_two_points(x1, y1, x2, y2, &a1, &b1, &c1);
  straight_line_passing_through_the_two_points(x3, y3, x4, y4, &a2, &b2, &c2);
  double c_x, c_y;
  bool is_parallel =
      intersection_and_parallel(a1, b1, c1, a2, b2, c2, &c_x, &c_y);
  if (is_parallel == false) {
    if ((a1 == a2 && b1 == b2 && c1 == c2) ||
        (a1 == 0 && (b1 / b2) == (c1 / c2)) ||
        (b1 == 0 && (a1 / a2) == (c1 / c2))) { // 一直線上にある.
      // cout<<1111;
      if (min(x1, x2) <= x3 && x3 <= max(x1, x2) && min(y1, y2) <= y3 &&
          y3 <= max(y1, y2))
        return 1;
      if (min(x1, x2) <= x4 && x4 <= max(x1, x2) && min(y1, y2) <= y4 &&
          y4 <= max(y1, y2))
        return 1;
      if (min(x3, x4) <= x1 && x1 <= max(x3, x4) && min(y3, y4) <= y1 &&
          y1 <= max(y3, y4))
        return 1;
      if (min(x3, x4) <= x2 && x2 <= max(x3, x4) && min(y3, y4) <= y2 &&
          y2 <= max(y3, y4))
        return 1;
    }
    return 0;
  }
  if (x1 > x2)
    swap(x1, x2);
  if (x3 > x4)
    swap(x3, x4);
  if (y1 > y2)
    swap(y1, y2);
  if (y3 > y4)
    swap(y3, y4);

  if (x1 <= c_x && c_x <= x2 && x3 <= c_x && c_x <= x4) {
    if (y1 <= c_y && c_y <= y2 && y3 <= c_y && c_y <= y4)
      return 1;
  }
  return 0;
}

//-------------------------------------------------------------------------------------
/*点(p_x,p_y)と線分(x1,y1)(x2,y2)の距離*/
/* straight_line_passing_through_the_two_points */
/* vertical_straight_line */
/* intersection_and_parallel */
double distance_between_the_line_segment_and_point(double p_x, double p_y,
                                                   double x1, double y1,
                                                   double x2, double y2) {
  double a, b, c; //(x1,y1)(x2,y2)を通る直線
  straight_line_passing_through_the_two_points(x1, y1, x2, y2, &a, &b, &c);
  double a2, b2, c2; // 直線ax+by+c=0に垂直な直線
  double v_x, v_y;   // 二つの直線の交点
  bool is_not_parallel =
      vertical_straight_line(p_x, p_y, a, b, c, &a2, &b2, &c2);
  intersection_and_parallel(a, b, c, a2, b2, c2, &v_x, &v_y);

  if (is_not_parallel) {
    if (min(x1, x2) <= v_x && v_x <= max(x1, x2) && min(y1, y2) <= v_y &&
        v_y <= max(y1, y2)) { //(v_x,v_y)は線分の中にある
      // cout<<"a ";
      return distance_between_the_two_pointss(p_x, p_y, v_x, v_y);
    } else { //(v_x,v_y)は線分の外にある
      double l1 = distance_between_the_two_pointss(p_x, p_y, x1, y1);
      double l2 = distance_between_the_two_pointss(p_x, p_y, x2, y2);
      // cout<<"b ";
      return min(l1, l2);
    }
  } else {
    if (min(x1, x2) <= p_x && p_x <= max(x1, x2) && min(y1, y2) <= p_y &&
        p_y <= max(y1, y2)) { //(p_x,p_y)は線分の中にある
      // cout<<"c ";
      return 0.0;
    } else { //(p_x,p_y)は線分の外にある
      double l1 = distance_between_the_two_pointss(p_x, p_y, x1, y1);
      double l2 = distance_between_the_two_pointss(p_x, p_y, x2, y2);
      // cout<<"d ";
      return min(l1, l2);
    }
  }
}

//-------------------------------------------------------------------------------------
/*線分(x1,y1)(x2,y2)と線分(x3,y3)(x4,y4)の距離*/

double distance_between_two_line_segment(double x1, double y1, double x2,
                                         double y2, double x3, double y3,
                                         double x4, double y4) {
  // 同一直線上にある場合

  // ぶつかる場合
  if (line_segment_cross_decision(x1, y1, x2, y2, x3, y3, x4, y4)) {
    return 0.0;
  }

  // ぶつからない場合
  double l1, l2, l3, l4;
  l1 = distance_between_the_line_segment_and_point(x1, y1, x3, y3, x4, y4);
  // cout<<l1<<endl;
  l2 = distance_between_the_line_segment_and_point(x2, y2, x3, y3, x4, y4);
  // cout<<l2<<endl;

  l3 = distance_between_the_line_segment_and_point(x3, y3, x1, y1, x2, y2);
  // cout<<l3<<endl;
  l4 = distance_between_the_line_segment_and_point(x4, y4, x1, y1, x2, y2);

  // cout<<l4<<endl;

  return min(l1, min(l2, min(l3, l4)));
}

//-------------------------------------------------------------------------------------
/*多角形の面積*/
/*頂点数n　頂点の集合 */
double area_of_the_polygon(int n, double p_xy[10000][2]) {
  double s = 0.0;
  for (int i = 0; i < n; i++) {
    s += (p_xy[i][0] - p_xy[(i + 1) % n][0]) *
         (p_xy[i][1] + p_xy[(i + 1) % n][1]) / 2;
  }
  return s;
}

//-------------------------------------------------------------------------------------
/*角abcの角度　a(xa,ya), b(xb,yb), c(xc,yc),*/
/*2辺の角度*/
/*aとb　またはbとcが重なっていればPIを返す*/
double angle_of_the_two_edges(double ax, double ay, double bx, double by,
                              double cx, double cy) {
  if (ax == bx && ay == by)
    return M_PI;
  if (cx == bx && cy == by)
    return M_PI;

  double angle1 = angle_of_the_line(ax, ay, bx, by);
  double angle2 = angle_of_the_line(bx, by, cx, cy);

  double ret = angle1 + (M_PI - angle2);
  if (ret > M_PI * 2)
    ret -= M_PI * 2;
  if (ret < 0)
    ret += M_PI * 2;
  return ret;
}

//-------------------------------------------------------------------------------------
/*多角形に対する点の内外判定*/
/* n頂点の多角形p_xy[n]に対して点(x,y)の内外判定を行う*/
/* 内なら2 線上なら1 外なら0*/
int inside_and_outside_the_determination_of_the_polygon_and_point(
    int n, double p_xy[10000][2], double x, double y) {
  // 点が線分上にあるか
  for (int i = 0; i < n; i++) {
    double l = distance_between_the_line_segment_and_point(
        x, y, p_xy[i][0], p_xy[i][1], p_xy[(i + 1) % n][0],
        p_xy[(i + 1) % n][1]);
    if (l == 0.0)
      return 1;
  }

  // 点が中にあるか外にあるか
  int ans = 0;
  for (int i = 0; i < n; i++) {
    if (p_xy[i][0] != p_xy[(i + 1) % n][0]) {
      ans += line_segment_cross_decision(
          p_xy[i][0], p_xy[i][1], p_xy[(i + 1) % n][0], p_xy[(i + 1) % n][1], x,
          y, x, y + 1000000.0);

      if (distance_between_the_line_segment_and_point(
              p_xy[i][0], p_xy[i][1], x, y, x, y + 1000000.0) == 0.0) {
        if (p_xy[i][0] > p_xy[(i + 1) % n][0])
          ans--;
      }
      if (distance_between_the_line_segment_and_point(
              p_xy[(i + 1) % n][0], p_xy[(i + 1) % n][1], x, y, x,
              y + 1000000.0) == 0.0) {
        if (p_xy[i][0] < p_xy[(i + 1) % n][0])
          ans--;
      }
    }
  }
  // cout<<" "<<ans<<" ";
  if (ans % 2 == 0)
    return 0;
  else
    return 2;
}
//-------------------------------------------------------------------------------------
/*二点の角度*/
/*0~2π*/
double angle_line_0_359(double x1, double y1, double x2, double y2) {
  double angle = atan2(y2 - y1, x2 - x1);
  if (angle < 0)
    angle = 2 * M_PI + angle;
  return angle;
}

//-------------------------------------------------------------------------------------
/*二辺の角度*/
/*反時計回りの内側*/
/*0~2π*/
double angle_two_line_0_359(double x1, double y1, double x2, double y2,
                            double x3, double y3) {
  double angle = atan2(y2 - y1, x2 - x1);
  if (angle < 0)
    angle = 2 * M_PI + angle;
  if (angle == 2 * M_PI)
    angle = 0.0;

  double angle2 = atan2(y3 - y2, x3 - x2);
  if (angle2 < 0)
    angle2 = 2 * M_PI + angle2;
  if (angle2 == 2 * M_PI)
    angle2 = 0.0;

  return angle + (M_PI - angle2);
}

//-------------------------------------------------------------------------------------
/*二次元配列のクイックソート*/
/*xoryが0ならx座標　1なら座標でソート*/
void two_dimensional_qsort(double xy[100000][2], int left, int right,
                           int xory) {
  int i, j;
  double pivot, pivot2;

  i = left;  /* ソートする配列の一番小さい要素の添字 */
  j = right; /* ソートする配列の一番大きい要素の添字 */

  pivot = xy[(left + right) / 2][xory]; /* 基準値を配列の中央付近にとる */
  pivot2 = xy[(left + right) / 2][(xory + 1) % 2];

  while (1) { /* 無限ループ */

    while (xy[i][xory] < pivot ||
           (xy[i][xory] == pivot &&
            xy[i][(xory + 1) % 2] < pivot2)) /* pivot より大きい値が */
      i++; /* 出るまで i を増加させる */

    while (pivot < xy[j][xory] ||
           (xy[j][xory] == pivot &&
            pivot2 < xy[j][(xory + 1) % 2])) /* pivot より小さい値が */
      j--;      /*  出るまで j を減少させる */
    if (i >= j) /* i >= j なら */
      break;    /* 無限ループから抜ける */

    swap(xy[i][xory], xy[j][xory]); /* x[i] と x[j]を交換 */
    swap(xy[i][(xory + 1) % 2], xy[j][(xory + 1) % 2]); /* x[i] と x[j]を交換 */
    i++;                                                /* 次のデータ */
    j--;
  }

  if (left < i - 1) /* 基準値の左に 2 以上要素があれば */
    two_dimensional_qsort(xy, left, i - 1, xory); /* 左の配列を Q ソートする */
  if (j + 1 < right) /* 基準値の右に 2 以上要素があれば */
    two_dimensional_qsort(xy, j + 1, right, xory); /* 右の配列を Q ソートする */
}

//-------------------------------------------------------------------------------------
/*凸包*/
/*２次元平面における点の集合Pに対する凸包（convex
 * hull）を求めて下さい。凸包とは点集合Pの全ての点を含む最小の凸多角形です。*/
/*集合の要素数 n*/
/*集合 p_xy[1000000][2]*/
/*解答の要素数 q*/
/*解答 ans[1000000][2]　最も下の最も左から反時計回り*/

void convex_hull(int n, double p_xy[100000][2], int *q, double ans[100000][2]) {

  two_dimensional_qsort(p_xy, 0, n - 1, 1);
  /*
  for(int i=0; i<n; i++){
      cout<<p_xy[i][0]<<" "<<p_xy[i][1]<<endl;
  }
   */

  int k = 0;
  for (int i = 0; i < n; i++) {
    while (k > 1 &&
           (angle_two_line_0_359(ans[k - 2][0], ans[k - 2][1], ans[k - 1][0],
                                 ans[k - 1][1], p_xy[i][0], p_xy[i][1]) > M_PI))
      k--;
    ans[k][0] = p_xy[i][0];
    ans[k][1] = p_xy[i][1];
    k++;
  }

  int t = k;
  for (int i = n - 2; i >= 0; i--) {
    while (k > t &&
           (angle_two_line_0_359(ans[k - 2][0], ans[k - 2][1], ans[k - 1][0],
                                 ans[k - 1][1], p_xy[i][0], p_xy[i][1]) > M_PI))
      k--;
    ans[k][0] = p_xy[i][0];
    ans[k][1] = p_xy[i][1];
    k++;
  }

  *q = k - 1;
}
int main(int argc, const char *argv[]) {
  // cout<<angle_two_line_0_359(0,0, 2,1,4,2)/M_PI<<endl;

  // cout<<angle_of_the_line(0,0,0,0)/M_PI * 180<<endl;
  // cout<<angle_line_0_359(1, 3,2, 2)/M_PI*180.0<<endl;
  // cout<<angle_line_0_359(1, 3,0, 0)/M_PI*180.0<<endl;

  int n;
  while (cin >> n) {
    double p_xy[100000][2] = {0};
    for (int i = 0; i < n; i++) {
      cin >> p_xy[i][0] >> p_xy[i][1];
    }

    two_dimensional_qsort(p_xy, 0, n - 1, 1);
    /*
    for(int i=0; i<n; i++){
        cout<<p_xy[i][0]<<" "<<p_xy[i][1]<<endl;
    }
    */
    int q;
    double ans[100000][2] = {0};
    convex_hull(n, p_xy, &q, ans);
    cout << q << endl;
    for (int i = 0; i < q; i++) {
      cout << ans[i][0] << " " << ans[i][1] << endl;
    }
  }
}

Error: TLE

Fixed submission:

#include <cmath>
#include <iomanip>
#include <iostream>
#include <math.h>

using namespace std;

//-------------------------------------------------------------------------------------
/*2点[(x1,y1),(x2,y2)]を入力し二点を通る直線ax+by+cの(a,b,c)を返す,  */
/*x1==x2ならfalseを返す*/
/*falseならばx=cの形の直線*/
void straight_line_passing_through_the_two_points(double x1, double y1,
                                                  double x2, double y2,
                                                  double *a, double *b,
                                                  double *c) {
  *a = (y2 - y1);
  *b = -(x2 - x1);
  *c = y2 * (x2 - x1) - x2 * (y2 - y1);
}

//-------------------------------------------------------------------------------------
/*(x,y)を通るa1x+b1y+c1=0に垂直な直線a2x+b2y+c2=0を返す*/
bool vertical_straight_line(double x, double y, double a1, double b1, double c1,
                            double *a2, double *b2, double *c2) {
  if (a1 * x + b1 * y + c1 == 0)
    return false;
  *a2 = -b1;
  *b2 = a1;
  *c2 = b1 * x - a1 * y;
  return true;
}

//-------------------------------------------------------------------------------------
/*2直線 a1x+b1y+c1=0 a2x+b2y+c2=0 の交点 (x,y)を返す*/
/*2直線が平行であるならば0を返す*/
int intersection_and_parallel(double a1, double b1, double c1, double a2,
                              double b2, double c2, double *x, double *y) {
  if (a1 * b2 == a2 * b1)
    return false; // 平行の判定

  *x = (b1 * c2 - b2 * c1) / (a1 * b2 - a2 * b1);
  *y = (a2 * c1 - a1 * c2) / (a1 * b2 - a2 * b1);

  return true;
}

//-------------------------------------------------------------------------------------
/*
 a1x+b1y+c1=0 と　a2x+b2y+c2=0 が
 平行なら2
 直交なら1
 それ以外は0
 を返す
 */
int judges_whether_parallel_or_perpendicular(double a1, double b1, double c1,
                                             double a2, double b2, double c2) {
  if (a1 * b2 == a2 * b1)
    return 2;
  if (a1 * a2 + b1 * b2 == 0)
    return 1;
  return 0;
}

//-------------------------------------------------------------------------------------
/*直線ax+by+c=0に対し　(x1,y1)と線対称な位置(x2,y2)を出力*/
/*vertical_straight_lineを使用*/
/*intersection_and_parallelを使用*/
void line_symmetry(double a, double b, double c, double x1, double y1,
                   double *x2, double *y2) {
  // 垂直な直線を求める
  double a2, b2, c2;
  vertical_straight_line(x1, y1, a, b, c, &a2, &b2, &c2);

  // 垂直な直線との交点を求める
  double c_x, c_y;
  intersection_and_parallel(a, b, c, a2, b2, c2, &c_x, &c_y);
  *x2 = x1 + 2 * (c_x - x1);
  *y2 = y1 + 2 * (c_y - y1);
}

//-------------------------------------------------------------------------------------
/*2点(x1,y1), (x2,y2) の距離*/
double distance_between_the_two_pointss(double x1, double y1, double x2,
                                        double y2) {
  return sqrt(fabs((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)));
}

//-------------------------------------------------------------------------------------
/* (x1,y1)から(x2,y2)へ伸ばした直線の角度を求める  */
/*-π　〜　+π　まで*/
double angle_of_the_line(double x1, double y1, double x2, double y2) {
  return atan2(y2 - y1, x2 - x1);
}

//-------------------------------------------------------------------------------------
/*(x1,y1)と(x2,y2)を両端に持つ線分と*/
/*(x3,y3)と(x4,y4)を両端に持つ線分が*/
/*交差するなら1 交差しないなら0を出力する*/
/* straight_line_passing_through_the_two_pointsを使用 */
/* intersection_and_parallelを使用 */
int line_segment_cross_decision(double x1, double y1, double x2, double y2,
                                double x3, double y3, double x4, double y4) {
  double a1, b1, c1, a2, b2, c2;
  straight_line_passing_through_the_two_points(x1, y1, x2, y2, &a1, &b1, &c1);
  straight_line_passing_through_the_two_points(x3, y3, x4, y4, &a2, &b2, &c2);
  double c_x, c_y;
  bool is_parallel =
      intersection_and_parallel(a1, b1, c1, a2, b2, c2, &c_x, &c_y);
  if (is_parallel == false) {
    if ((a1 == a2 && b1 == b2 && c1 == c2) ||
        (a1 == 0 && (b1 / b2) == (c1 / c2)) ||
        (b1 == 0 && (a1 / a2) == (c1 / c2))) { // 一直線上にある.
      // cout<<1111;
      if (min(x1, x2) <= x3 && x3 <= max(x1, x2) && min(y1, y2) <= y3 &&
          y3 <= max(y1, y2))
        return 1;
      if (min(x1, x2) <= x4 && x4 <= max(x1, x2) && min(y1, y2) <= y4 &&
          y4 <= max(y1, y2))
        return 1;
      if (min(x3, x4) <= x1 && x1 <= max(x3, x4) && min(y3, y4) <= y1 &&
          y1 <= max(y3, y4))
        return 1;
      if (min(x3, x4) <= x2 && x2 <= max(x3, x4) && min(y3, y4) <= y2 &&
          y2 <= max(y3, y4))
        return 1;
    }
    return 0;
  }
  if (x1 > x2)
    swap(x1, x2);
  if (x3 > x4)
    swap(x3, x4);
  if (y1 > y2)
    swap(y1, y2);
  if (y3 > y4)
    swap(y3, y4);

  if (x1 <= c_x && c_x <= x2 && x3 <= c_x && c_x <= x4) {
    if (y1 <= c_y && c_y <= y2 && y3 <= c_y && c_y <= y4)
      return 1;
  }
  return 0;
}

//-------------------------------------------------------------------------------------
/*点(p_x,p_y)と線分(x1,y1)(x2,y2)の距離*/
/* straight_line_passing_through_the_two_points */
/* vertical_straight_line */
/* intersection_and_parallel */
double distance_between_the_line_segment_and_point(double p_x, double p_y,
                                                   double x1, double y1,
                                                   double x2, double y2) {
  double a, b, c; //(x1,y1)(x2,y2)を通る直線
  straight_line_passing_through_the_two_points(x1, y1, x2, y2, &a, &b, &c);
  double a2, b2, c2; // 直線ax+by+c=0に垂直な直線
  double v_x, v_y;   // 二つの直線の交点
  bool is_not_parallel =
      vertical_straight_line(p_x, p_y, a, b, c, &a2, &b2, &c2);
  intersection_and_parallel(a, b, c, a2, b2, c2, &v_x, &v_y);

  if (is_not_parallel) {
    if (min(x1, x2) <= v_x && v_x <= max(x1, x2) && min(y1, y2) <= v_y &&
        v_y <= max(y1, y2)) { //(v_x,v_y)は線分の中にある
      // cout<<"a ";
      return distance_between_the_two_pointss(p_x, p_y, v_x, v_y);
    } else { //(v_x,v_y)は線分の外にある
      double l1 = distance_between_the_two_pointss(p_x, p_y, x1, y1);
      double l2 = distance_between_the_two_pointss(p_x, p_y, x2, y2);
      // cout<<"b ";
      return min(l1, l2);
    }
  } else {
    if (min(x1, x2) <= p_x && p_x <= max(x1, x2) && min(y1, y2) <= p_y &&
        p_y <= max(y1, y2)) { //(p_x,p_y)は線分の中にある
      // cout<<"c ";
      return 0.0;
    } else { //(p_x,p_y)は線分の外にある
      double l1 = distance_between_the_two_pointss(p_x, p_y, x1, y1);
      double l2 = distance_between_the_two_pointss(p_x, p_y, x2, y2);
      // cout<<"d ";
      return min(l1, l2);
    }
  }
}

//-------------------------------------------------------------------------------------
/*線分(x1,y1)(x2,y2)と線分(x3,y3)(x4,y4)の距離*/

double distance_between_two_line_segment(double x1, double y1, double x2,
                                         double y2, double x3, double y3,
                                         double x4, double y4) {
  // 同一直線上にある場合

  // ぶつかる場合
  if (line_segment_cross_decision(x1, y1, x2, y2, x3, y3, x4, y4)) {
    return 0.0;
  }

  // ぶつからない場合
  double l1, l2, l3, l4;
  l1 = distance_between_the_line_segment_and_point(x1, y1, x3, y3, x4, y4);
  // cout<<l1<<endl;
  l2 = distance_between_the_line_segment_and_point(x2, y2, x3, y3, x4, y4);
  // cout<<l2<<endl;

  l3 = distance_between_the_line_segment_and_point(x3, y3, x1, y1, x2, y2);
  // cout<<l3<<endl;
  l4 = distance_between_the_line_segment_and_point(x4, y4, x1, y1, x2, y2);

  // cout<<l4<<endl;

  return min(l1, min(l2, min(l3, l4)));
}

//-------------------------------------------------------------------------------------
/*多角形の面積*/
/*頂点数n　頂点の集合 */
double area_of_the_polygon(int n, double p_xy[10000][2]) {
  double s = 0.0;
  for (int i = 0; i < n; i++) {
    s += (p_xy[i][0] - p_xy[(i + 1) % n][0]) *
         (p_xy[i][1] + p_xy[(i + 1) % n][1]) / 2;
  }
  return s;
}

//-------------------------------------------------------------------------------------
/*角abcの角度　a(xa,ya), b(xb,yb), c(xc,yc),*/
/*2辺の角度*/
/*aとb　またはbとcが重なっていればPIを返す*/
double angle_of_the_two_edges(double ax, double ay, double bx, double by,
                              double cx, double cy) {
  if (ax == bx && ay == by)
    return M_PI;
  if (cx == bx && cy == by)
    return M_PI;

  double angle1 = angle_of_the_line(ax, ay, bx, by);
  double angle2 = angle_of_the_line(bx, by, cx, cy);

  double ret = angle1 + (M_PI - angle2);
  if (ret > M_PI * 2)
    ret -= M_PI * 2;
  if (ret < 0)
    ret += M_PI * 2;
  return ret;
}

//-------------------------------------------------------------------------------------
/*多角形に対する点の内外判定*/
/* n頂点の多角形p_xy[n]に対して点(x,y)の内外判定を行う*/
/* 内なら2 線上なら1 外なら0*/
int inside_and_outside_the_determination_of_the_polygon_and_point(
    int n, double p_xy[10000][2], double x, double y) {
  // 点が線分上にあるか
  for (int i = 0; i < n; i++) {
    double l = distance_between_the_line_segment_and_point(
        x, y, p_xy[i][0], p_xy[i][1], p_xy[(i + 1) % n][0],
        p_xy[(i + 1) % n][1]);
    if (l == 0.0)
      return 1;
  }

  // 点が中にあるか外にあるか
  int ans = 0;
  for (int i = 0; i < n; i++) {
    if (p_xy[i][0] != p_xy[(i + 1) % n][0]) {
      ans += line_segment_cross_decision(
          p_xy[i][0], p_xy[i][1], p_xy[(i + 1) % n][0], p_xy[(i + 1) % n][1], x,
          y, x, y + 1000000.0);

      if (distance_between_the_line_segment_and_point(
              p_xy[i][0], p_xy[i][1], x, y, x, y + 1000000.0) == 0.0) {
        if (p_xy[i][0] > p_xy[(i + 1) % n][0])
          ans--;
      }
      if (distance_between_the_line_segment_and_point(
              p_xy[(i + 1) % n][0], p_xy[(i + 1) % n][1], x, y, x,
              y + 1000000.0) == 0.0) {
        if (p_xy[i][0] < p_xy[(i + 1) % n][0])
          ans--;
      }
    }
  }
  // cout<<" "<<ans<<" ";
  if (ans % 2 == 0)
    return 0;
  else
    return 2;
}
//-------------------------------------------------------------------------------------
double angle_line_0_359(double x1, double y1, double x2, double y2) {
  double angle = atan2(y2 - y1, x2 - x1);
  if (angle < 0)
    angle = 2 * M_PI + angle;
  return angle;
}

//-------------------------------------------------------------------------------------
/*凸包*/
/*２次元平面における点の集合Pに対する凸包（convex
 * hull）を求めて下さい。凸包とは点集合Pの全ての点を含む最小の凸多角形です。*/
/*集合の要素数 n*/
/*集合 p_xy[1000000][2]*/
/*解答の要素数 q*/
/*解答 ans[1000000][2]　最も下の最も左から反時計回り*/
void convex_hull(int n, double p_xy[100000][2], int *q, double ans[100000][2]) {

  int lower_left = 0;
  for (int i = 1; i < n; i++) {
    if (p_xy[lower_left][1] > p_xy[i][1]) {
      lower_left = i;
    } else if (p_xy[lower_left][1] == p_xy[i][1] &&
               p_xy[lower_left][0] > p_xy[i][0]) {
      lower_left = i;
    }
  }

  ans[0][0] = p_xy[lower_left][0];
  ans[0][1] = p_xy[lower_left][1];
  *q = 1;

  n--;
  p_xy[lower_left][0] = p_xy[n][0];
  p_xy[lower_left][1] = p_xy[n][1];

  while (1) {
    double angle = 999999.9;
    int next = -1;
    for (int i = 0; i < n; i++) {
      if (p_xy[i][1] < ans[*q - 1][1])
        continue;
      double temp_angle = angle_line_0_359(ans[*q - 1][0], ans[*q - 1][1],
                                           p_xy[i][0], p_xy[i][1]);
      if (0 <= temp_angle && temp_angle <= M_PI && temp_angle < angle) {
        angle = temp_angle;
        next = i;
      }

      if (temp_angle == angle) {
        if (distance_between_the_two_pointss(ans[*q - 1][0], ans[*q - 1][1],
                                             p_xy[i][0], p_xy[i][1]) <
            distance_between_the_two_pointss(ans[*q - 1][0], ans[*q - 1][1],
                                             p_xy[next][0], p_xy[next][1])) {
          next = i;
        }
      }
    }

    // double angle2 = angle_line_0_359(p_xy[next][0], p_xy[next][1],ans[0][0],
    // ans[0][1]); if(angle>angle2)break;
    if (next == -1)
      break;
    else {
      ans[*q][0] = p_xy[next][0];
      ans[*q][1] = p_xy[next][1];

      *q = *q + 1;

      n--;
      p_xy[next][0] = p_xy[n][0];
      p_xy[next][1] = p_xy[n][1];
    }
  }

  while (1) {
    double angle = 999999.9;
    int next = -1;
    for (int i = 0; i < n; i++) {
      if (p_xy[i][1] > ans[*q - 1][1])
        continue;

      double temp_angle = angle_line_0_359(ans[*q - 1][0], ans[*q - 1][1],
                                           p_xy[i][0], p_xy[i][1]);
      if (M_PI <= temp_angle && temp_angle < 2 * M_PI && temp_angle < angle) {
        angle = temp_angle;
        next = i;
      }

      if (temp_angle == angle) {
        if (distance_between_the_two_pointss(ans[*q - 1][0], ans[*q - 1][1],
                                             p_xy[i][0], p_xy[i][1]) <
            distance_between_the_two_pointss(ans[*q - 1][0], ans[*q - 1][1],
                                             p_xy[next][0], p_xy[next][1])) {
          next = i;
        }
      }
    }

    double angle2 =
        angle_line_0_359(p_xy[next][0], p_xy[next][1], ans[0][0], ans[0][1]);
    if (angle > angle2)
      break;
    // if(next==-1)break;
    else {
      ans[*q][0] = p_xy[next][0];
      ans[*q][1] = p_xy[next][1];

      *q = *q + 1;

      n--;
      p_xy[next][0] = p_xy[n][0];
      p_xy[next][1] = p_xy[n][1];
    }
  }
}
int main(int argc, const char *argv[]) {

  // cout<<angle_of_the_line(0,0,0,0)/M_PI * 180<<endl;
  // cout<<angle_line_0_359(1, 3,2, 2)/M_PI*180.0<<endl;
  // cout<<angle_line_0_359(1, 3,0, 0)/M_PI*180.0<<endl;

  int n;
  while (cin >> n) {
    double p_xy[100000][2] = {0};
    for (int i = 0; i < n; i++) {
      cin >> p_xy[i][0] >> p_xy[i][1];
    }
    int q;
    double ans[100000][2] = {0};
    convex_hull(n, p_xy, &q, ans);
    cout << q << endl;
    for (int i = 0; i < q; i++) {
      cout << ans[i][0] << " " << ans[i][1] << endl;
    }
  }
}