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

// 凸包
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <stack>
#include <vector>

#include <cassert>
#include <queue>

using namespace std;

// 浮動小数点のゼロ判定
#define EPS (1e-10)
#define equals(a, b) (fabs((a) - (b)) < EPS)

// 点を表すクラス
class Point {
public:
  double x, y;
  // コンストラクタ
  Point(double x = 0.0, double y = 0.0) : x(x), y(y) {}

  // -----▼▼▼ 演算子のオーバーロード ▼▼▼-----

  Point operator+(Point &p) { return Point(x + p.x, y + p.y); }

  Point operator-(Point &p) { return Point(x - p.x, y - p.y); }

  Point operator*(double a) { return Point(a * x, a * y); }

  Point operator/(double a) { return Point(x / a, y / a); }

  bool operator<(const Point &p) const { return x != p.x ? x < p.x : y < p.y; }

  bool operator<=(const Point &p) const {
    return x != p.x ? x <= p.x : y <= p.y;
  }

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

  // -----▲▲▲ 演算子のオーバーロード ▲▲▲-----

  // 22点間の距離の算出
  double distance() { return sqrt(norm()); }

  double norm() { return (x * x) + (y * y); }
};

// 線分を表すクラス
class Segment {
public:
  Point p1, p2;
  // コンストラクタ
  Segment(Point p1, Point p2) : p1(p1), p2(p2) {}
};

// 点とベクトルの表現は同じ
typedef Point Vector;
// 線分と直線の表現は同じ
typedef Segment Line;
// 多角形の表現
typedef vector<Point> Polygon;

// 円を表すくらす
class Circle {
public:
  Point c;  // 中心
  double r; // 半径

  Circle(Point c = Point(), double r = 0.0) : c(c), r(r) {}
};

double dot(Vector a, Vector b);
double cross(Vector a, Vector b);
double cross_point(Line line, Point pp);
Vector projection(Vector a, Vector b, Vector p);
Point project(Segment s, Point p);
double getDistanceLP(Line l, Point p);
int ccw(Point p0, Point p1, Point p2);
Point getCrossPoint(Segment s1, Segment s2);
pair<Point, Point> getCrossPoint(Circle circle, Line l);
pair<Point, Point> getCrossPoint(Circle c1, Circle c2);
int contains(Polygon g, Point p);
Polygon AndrewScan(Polygon pg);

int main(void) {
  int n, index;
  Point p, minPoint;
  Polygon poly, retPoly;

  cin >> n;

  for (int i = 0; i < n; i++) {
    // 各点の格納
    cin >> p.x >> p.y;
    // 多角形の作成
    poly.push_back(p);
    ;
  }

  retPoly = AndrewScan(poly);

  // -----▼▼▼ 表示のための処理 ▼▼▼-----

  // 凸多角形の頂点の一番下で、左端の点を探す
  index = 0;
  minPoint = retPoly[0];

  for (int i = 1; i < retPoly.size(); i++) {
    if (retPoly[i].y <= minPoint.y) {
      if (retPoly[i].y == minPoint.y) {
        if (retPoly[i].x < minPoint.x) {
          index = i;
          minPoint = retPoly[i];
        }
      } else {
        index = i;
        minPoint = retPoly[i];
      }
    }
  }

  cout << retPoly.size() << endl;

  for (int i = index; i < retPoly.size(); i++) {
    cout << retPoly[i].x << " " << retPoly[i].y << endl;
  }

  for (int i = 0; i < index; i++) {
    cout << retPoly[i].x << " " << retPoly[i].y << endl;
  }

  // -----▲▲▲ 表示のための処理 ▲▲▲-----

  return 0;
}

// 内積の計算をする関数
double dot(Vector a, Vector b) { return ((a.x * b.x) + (a.y * b.y)); }

// 外積の計算をする関数
double cross(Vector a, Vector b) { return ((a.x * b.y) - (a.y * b.x)); }

// 外積の計算をする関数 2
// 直線 : line に対する点pの外積の演算
double cross_point(Line line, Point pp) {
  return (line.p2.x - line.p1.x) * (pp.y - line.p1.y) -
         (pp.x - line.p1.x) * (line.p2.y - line.p1.y);
}

// 正射影ベクトルを求める関数
// p : 垂線の始点となる点
Vector projection(Vector a, Vector b, Vector p) {
  // 正射影ベクトルの考え方より
  // 正射影ベクトル = ( ( a, bベクトルの内積 ) / aベクトルの大きさの2乗 ) *
  // aベクトル
  return ((a * (dot(a, b) / pow(a.distance(), 2.0))) + p);
}

// 正射影ベクトルを求める関数 2
// p : 垂線の始点となる点
// 戻り値 : pからの垂線と直線：sの交点
Point project(Segment s, Point p) {
  Vector base = s.p2 - s.p1;
  double r = dot(p - s.p1, base) / base.norm();
  Point tp = base * r;
  return s.p1 + tp;
}

// 点と直線の距離を求める関数
double getDistanceLP(Line l, Point p) {
  if (dot(l.p2 - l.p1, p - l.p1) < 0.0) {
    // 内積の値が負の場合, 2つの線分のなす角が90°以上のため,
    // 距離は, p と l.p1 の距離そのものになる
    return (p - l.p1).distance();
  }

  if (dot(l.p1 - l.p2, p - l.p2) < 0.0) {
    // 内積の値が負の場合, 2つの線分のなす角が90°以上のため,
    // 距離は, p と l.p2 の距離そのものになる
    return (p - l.p2).distance();
  }

  // 2つの線分のなす角が90°以内の時
  return abs(cross(l.p2 - l.p1, p - l.p1) / (l.p2 - l.p1).distance());
}

static const int COUNTER_CLOCKWISE = 1;
static const int CLOCKWISE = -1;
static const int ONLINE_BACK = 2;
static const int ONLINE_FRONT = -2;
static const int ON_SEGMENT = 0;

// 3点の関係を調査する関数
int ccw(Point p0, Point p1, Point p2) {
  Vector a = p1 - p0;
  Vector b = p2 - p0;

  if (cross(a, b) > EPS) {
    // P2が半時計回りの方向にいる
    return COUNTER_CLOCKWISE;
  } else if (cross(a, b) < -EPS) {
    // P2が時計回りの方向にいる
    return CLOCKWISE;
  } else if (dot(a, b) < -EPS) {
    // P2が, 直線：p0p1に対して, 180°反対方向にいる
    return ONLINE_BACK;
  } else if (a.norm() < b.norm()) {
    // p0, p1, p2 の順で同一直線上に点が並んでいる
    return ONLINE_FRONT;
  }

  // p0, p2, p1 の順で同一直線上に点が並んでいる
  return ON_SEGMENT;
}

// -----▼▼▼ 線分の交差判定を実施する関数群 ▼▼▼-----

bool intersect(Point p1, Point p2, Point p3, Point p4) {
  return (ccw(p1, p2, p3) * ccw(p1, p2, p4) <= 0 &&
          ccw(p3, p4, p1) * ccw(p3, p4, p1) <= 0);
}

// 線分の交点が存在するかの確認
bool intersect(Segment s1, Segment s2) {
  return intersect(s1.p1, s1.p2, s2.p1, s2.p2);
}

// 円の交点が存在するかの確認
bool intersect(Circle c1, Circle c2) {
  return ((c2.c - c1.c).distance() <= c1.r + c2.r);
}

// -----▲▲▲ 線分の交差判定を実施する関数群 ▲▲▲-----

// 線分の交点を求める関数
Point getCrossPoint(Segment s1, Segment s2) {
  Point p0;
  double d1, d2, t;

  Vector base = s2.p2 - s2.p1;

  // 外積(平行四辺形の面積)から, 点と直線の距離を求める
  d1 = abs(cross(base, s1.p1 - s2.p1) / base.distance());
  d2 = abs(cross(base, s1.p2 - s2.p1) / base.distance());

  t = d1 / (d1 + d2);

  p0 = (s1.p2 - s1.p1) * t;

  return s1.p1 + p0;
}

// 円と直線の交点を求める関数
pair<Point, Point> getCrossPoint(Circle circle, Line l) {
  Point p0, p1;

  // 円の中心からの垂線と直線：lの交点：prを求める
  Vector pr = project(l, circle.c);

  if ((pr - circle.c).distance() > circle.r) {
    // 円と直線に交点が存在しない時
    return make_pair(p0, p1);
  }

  // 直線：l上の単位ベクトルを求める
  Vector e = (l.p2 - l.p1) / (l.p2 - l.p1).distance();
  // 交点：prと、円と直線の交点までの距離を求める
  double base = sqrt(circle.r * circle.r - (pr - circle.c).norm());

  // 円と直線の交点を求める
  Point eb = e * base;
  p0 = pr - eb;
  p1 = pr + eb;

  if (p1 < p0) {
    // 点の大小関係の調整
    p0 = pr + eb;
    p1 = pr - eb;
  }

  return make_pair(p0, p1);
}

// -----▼▼▼ 円の交点を求めるための関数一覧 ▼▼▼-----

// 与えられたベクトルのx軸となす角を求める関数
double arg(Vector v) { return atan2(v.y, v.x); }

// x軸上の点aを, x軸回りに角度θだけ回転させた点を求める関数
Point polar(double a, double theta) {
  return Point(cos(theta) * a, sin(theta) * a);
}

// 2つの円の交点を求める関数
pair<Point, Point> getCrossPoint(Circle c1, Circle c2) {
  Point p0, p1, pa, pb;

  // 円の交点が存在することの確認
  assert(intersect(c1, c2));
  // 円の中心間の距離を求める
  double d = (c2.c - c1.c).distance();
  // 余弦定理より, c1の半径と円の中心間の直線：dのなす角を求める
  double a = acos((c1.r * c1.r + d * d - c2.r * c2.r) / (2.0 * c1.r * d));
  // x軸とdがなす角を求める
  double t = arg(c2.c - c1.c);

  pa = polar(c1.r, t + a);
  p0 = c1.c + pa;
  pb = polar(c1.r, t - a);
  p1 = c1.c + pb;

  if (p1 < p0) {
    // 表示用の大小関係の確認
    p1 = c1.c + pa;
    p0 = c1.c + pb;
  }

  return make_pair(p0, p1);
}

// -----▲▲▲ 円の交点を求めるための関数一覧 ▲▲▲-----

// 指定された点が多角形に内包されるかを調べる関数
int contains(Polygon g, Point p) {
  int n = g.size();
  bool x = false;

  for (int i = 0; i < n; i++) {
    // 多角形の各点を, 点:pが原点となるように平行移動する
    Point a = g[i] - p;
    Point b = g[(i + 1) % n] - p;

    if (abs(cross(a, b)) < EPS && dot(a, b) < EPS) {
      // aベクトル, bベクトルが同一直線上で, 方向が反対
      // 点：pが, 多角形上の辺にいる時
      return 1;
    }

    if (a.y > b.y) {
      // aベクトルのyの値が小さくなるようにする
      swap(a, b);
    }

    if (a.y < EPS && EPS < b.y && cross(a, b) > EPS) {
      // aベクトルとbベクトルの終点が半直線をまたいで反対方向にある
      // bベクトルがaベクトルに対して, 半時計回りの方向にある
      x = !x;
    }
  }

  return (x ? 2 : 0);
}

// 凸包を求めるアンドリューのアルゴリズム
Polygon AndrewScan(Polygon s) {
  Polygon u, l;

  if (s.size() < 3) {
    return s;
  }

  // 点の集合をx軸について, 昇順に並び替える
  // ( クィックソートなので速度が早い )
  sort(s.begin(), s.end());

  // xが小さいものから, 2つ u に追加
  u.push_back(s[0]);
  u.push_back(s[1]);
  // xが大きいものから, 2つ l に追加
  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]) == COUNTER_CLOCKWISE; n--) {
      // 追加する点が, 直前の2点が作るベクトルに対して,
      // 反時計回りの方向にあるなら, 最後の点を削除する
      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]) == COUNTER_CLOCKWISE; n--) {
      // 追加する点が, 直前の2点が作るベクトルに対して,
      // 反時計回りの方向にあるなら, 最後の点を削除する
      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;
}


Error: TLE

Fixed submission:

// 凸包
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <stack>
#include <vector>

#include <cassert>
#include <queue>

using namespace std;

// 浮動小数点のゼロ判定
#define EPS (1e-10)
#define equals(a, b) (fabs((a) - (b)) < EPS)

// 点を表すクラス
class Point {
public:
  double x, y;
  // コンストラクタ
  Point(double x = 0.0, double y = 0.0) : x(x), y(y) {}

  // -----▼▼▼ 演算子のオーバーロード ▼▼▼-----

  Point operator+(Point &p) { return Point(x + p.x, y + p.y); }

  Point operator-(Point &p) { return Point(x - p.x, y - p.y); }

  Point operator*(double a) { return Point(a * x, a * y); }

  Point operator/(double a) { return Point(x / a, y / a); }

  bool operator<(const Point &p) const { return x != p.x ? x < p.x : y < p.y; }

  bool operator<=(const Point &p) const {
    return x != p.x ? x <= p.x : y <= p.y;
  }

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

  // -----▲▲▲ 演算子のオーバーロード ▲▲▲-----

  // 22点間の距離の算出
  double distance() { return sqrt(norm()); }

  double norm() { return (x * x) + (y * y); }
};

// 線分を表すクラス
class Segment {
public:
  Point p1, p2;
  // コンストラクタ
  Segment(Point p1, Point p2) : p1(p1), p2(p2) {}
};

// 点とベクトルの表現は同じ
typedef Point Vector;
// 線分と直線の表現は同じ
typedef Segment Line;
// 多角形の表現
typedef vector<Point> Polygon;

// 円を表すくらす
class Circle {
public:
  Point c;  // 中心
  double r; // 半径

  Circle(Point c = Point(), double r = 0.0) : c(c), r(r) {}
};

double dot(Vector a, Vector b);
double cross(Vector a, Vector b);
double cross_point(Line line, Point pp);
Vector projection(Vector a, Vector b, Vector p);
Point project(Segment s, Point p);
double getDistanceLP(Line l, Point p);
int ccw(Point p0, Point p1, Point p2);
Point getCrossPoint(Segment s1, Segment s2);
pair<Point, Point> getCrossPoint(Circle circle, Line l);
pair<Point, Point> getCrossPoint(Circle c1, Circle c2);
int contains(Polygon g, Point p);
Polygon AndrewScan(Polygon pg);

struct mP {
  int index;
  Point p;
} minPoint;

int main(void) {
  int n;
  Point p;
  Polygon poly, retPoly;

  cin >> n;

  for (int i = 0; i < n; i++) {
    // 各点の格納
    cin >> p.x >> p.y;
    // 多角形の作成
    poly.push_back(p);
    ;
  }

  retPoly = AndrewScan(poly);

  // -----▼▼▼ 表示のための処理 ▼▼▼-----

  cout << retPoly.size() << endl;

  for (int i = minPoint.index; i < retPoly.size(); i++) {
    cout << retPoly[i].x << " " << retPoly[i].y << endl;
  }

  for (int i = 0; i < minPoint.index; i++) {
    cout << retPoly[i].x << " " << retPoly[i].y << endl;
  }

  // -----▲▲▲ 表示のための処理 ▲▲▲-----

  return 0;
}

// 内積の計算をする関数
double dot(Vector a, Vector b) { return ((a.x * b.x) + (a.y * b.y)); }

// 外積の計算をする関数
double cross(Vector a, Vector b) { return ((a.x * b.y) - (a.y * b.x)); }

// 外積の計算をする関数 2
// 直線 : line に対する点pの外積の演算
double cross_point(Line line, Point pp) {
  return (line.p2.x - line.p1.x) * (pp.y - line.p1.y) -
         (pp.x - line.p1.x) * (line.p2.y - line.p1.y);
}

// 正射影ベクトルを求める関数
// p : 垂線の始点となる点
Vector projection(Vector a, Vector b, Vector p) {
  // 正射影ベクトルの考え方より
  // 正射影ベクトル = ( ( a, bベクトルの内積 ) / aベクトルの大きさの2乗 ) *
  // aベクトル
  return ((a * (dot(a, b) / pow(a.distance(), 2.0))) + p);
}

// 正射影ベクトルを求める関数 2
// p : 垂線の始点となる点
// 戻り値 : pからの垂線と直線：sの交点
Point project(Segment s, Point p) {
  Vector base = s.p2 - s.p1;
  double r = dot(p - s.p1, base) / base.norm();
  Point tp = base * r;
  return s.p1 + tp;
}

// 点と直線の距離を求める関数
double getDistanceLP(Line l, Point p) {
  if (dot(l.p2 - l.p1, p - l.p1) < 0.0) {
    // 内積の値が負の場合, 2つの線分のなす角が90°以上のため,
    // 距離は, p と l.p1 の距離そのものになる
    return (p - l.p1).distance();
  }

  if (dot(l.p1 - l.p2, p - l.p2) < 0.0) {
    // 内積の値が負の場合, 2つの線分のなす角が90°以上のため,
    // 距離は, p と l.p2 の距離そのものになる
    return (p - l.p2).distance();
  }

  // 2つの線分のなす角が90°以内の時
  return abs(cross(l.p2 - l.p1, p - l.p1) / (l.p2 - l.p1).distance());
}

static const int COUNTER_CLOCKWISE = 1;
static const int CLOCKWISE = -1;
static const int ONLINE_BACK = 2;
static const int ONLINE_FRONT = -2;
static const int ON_SEGMENT = 0;

// 3点の関係を調査する関数
int ccw(Point p0, Point p1, Point p2) {
  Vector a = p1 - p0;
  Vector b = p2 - p0;

  if (cross(a, b) > EPS) {
    // P2が半時計回りの方向にいる
    return COUNTER_CLOCKWISE;
  } else if (cross(a, b) < -EPS) {
    // P2が時計回りの方向にいる
    return CLOCKWISE;
  } else if (dot(a, b) < -EPS) {
    // P2が, 直線：p0p1に対して, 180°反対方向にいる
    return ONLINE_BACK;
  } else if (a.norm() < b.norm()) {
    // p0, p1, p2 の順で同一直線上に点が並んでいる
    return ONLINE_FRONT;
  }

  // p0, p2, p1 の順で同一直線上に点が並んでいる
  return ON_SEGMENT;
}

// -----▼▼▼ 線分の交差判定を実施する関数群 ▼▼▼-----

bool intersect(Point p1, Point p2, Point p3, Point p4) {
  return (ccw(p1, p2, p3) * ccw(p1, p2, p4) <= 0 &&
          ccw(p3, p4, p1) * ccw(p3, p4, p1) <= 0);
}

// 線分の交点が存在するかの確認
bool intersect(Segment s1, Segment s2) {
  return intersect(s1.p1, s1.p2, s2.p1, s2.p2);
}

// 円の交点が存在するかの確認
bool intersect(Circle c1, Circle c2) {
  return ((c2.c - c1.c).distance() <= c1.r + c2.r);
}

// -----▲▲▲ 線分の交差判定を実施する関数群 ▲▲▲-----

// 線分の交点を求める関数
Point getCrossPoint(Segment s1, Segment s2) {
  Point p0;
  double d1, d2, t;

  Vector base = s2.p2 - s2.p1;

  // 外積(平行四辺形の面積)から, 点と直線の距離を求める
  d1 = abs(cross(base, s1.p1 - s2.p1) / base.distance());
  d2 = abs(cross(base, s1.p2 - s2.p1) / base.distance());

  t = d1 / (d1 + d2);

  p0 = (s1.p2 - s1.p1) * t;

  return s1.p1 + p0;
}

// 円と直線の交点を求める関数
pair<Point, Point> getCrossPoint(Circle circle, Line l) {
  Point p0, p1;

  // 円の中心からの垂線と直線：lの交点：prを求める
  Vector pr = project(l, circle.c);

  if ((pr - circle.c).distance() > circle.r) {
    // 円と直線に交点が存在しない時
    return make_pair(p0, p1);
  }

  // 直線：l上の単位ベクトルを求める
  Vector e = (l.p2 - l.p1) / (l.p2 - l.p1).distance();
  // 交点：prと、円と直線の交点までの距離を求める
  double base = sqrt(circle.r * circle.r - (pr - circle.c).norm());

  // 円と直線の交点を求める
  Point eb = e * base;
  p0 = pr - eb;
  p1 = pr + eb;

  if (p1 < p0) {
    // 点の大小関係の調整
    p0 = pr + eb;
    p1 = pr - eb;
  }

  return make_pair(p0, p1);
}

// -----▼▼▼ 円の交点を求めるための関数一覧 ▼▼▼-----

// 与えられたベクトルのx軸となす角を求める関数
double arg(Vector v) { return atan2(v.y, v.x); }

// x軸上の点aを, x軸回りに角度θだけ回転させた点を求める関数
Point polar(double a, double theta) {
  return Point(cos(theta) * a, sin(theta) * a);
}

// 2つの円の交点を求める関数
pair<Point, Point> getCrossPoint(Circle c1, Circle c2) {
  Point p0, p1, pa, pb;

  // 円の交点が存在することの確認
  assert(intersect(c1, c2));
  // 円の中心間の距離を求める
  double d = (c2.c - c1.c).distance();
  // 余弦定理より, c1の半径と円の中心間の直線：dのなす角を求める
  double a = acos((c1.r * c1.r + d * d - c2.r * c2.r) / (2.0 * c1.r * d));
  // x軸とdがなす角を求める
  double t = arg(c2.c - c1.c);

  pa = polar(c1.r, t + a);
  p0 = c1.c + pa;
  pb = polar(c1.r, t - a);
  p1 = c1.c + pb;

  if (p1 < p0) {
    // 表示用の大小関係の確認
    p1 = c1.c + pa;
    p0 = c1.c + pb;
  }

  return make_pair(p0, p1);
}

// -----▲▲▲ 円の交点を求めるための関数一覧 ▲▲▲-----

// 指定された点が多角形に内包されるかを調べる関数
int contains(Polygon g, Point p) {
  int n = g.size();
  bool x = false;

  for (int i = 0; i < n; i++) {
    // 多角形の各点を, 点:pが原点となるように平行移動する
    Point a = g[i] - p;
    Point b = g[(i + 1) % n] - p;

    if (abs(cross(a, b)) < EPS && dot(a, b) < EPS) {
      // aベクトル, bベクトルが同一直線上で, 方向が反対
      // 点：pが, 多角形上の辺にいる時
      return 1;
    }

    if (a.y > b.y) {
      // aベクトルのyの値が小さくなるようにする
      swap(a, b);
    }

    if (a.y < EPS && EPS < b.y && cross(a, b) > EPS) {
      // aベクトルとbベクトルの終点が半直線をまたいで反対方向にある
      // bベクトルがaベクトルに対して, 半時計回りの方向にある
      x = !x;
    }
  }

  return (x ? 2 : 0);
}

// 一番左端かつ下の点を求めるための関数
void setMinPoint(Point point, int index) {
  static int count = 0;

  if (count == 0) {
    // 凸多角形の頂点の一番下で、左端の点を探す
    minPoint.p = point;
    count++;
    return;
  }

  if (point.y <= minPoint.p.y) {
    if (point.y == minPoint.p.y) {
      if (point.x < minPoint.p.x) {
        minPoint.index = index;
        minPoint.p = point;
      }
    } else {
      minPoint.index = index;
      minPoint.p = point;
    }
  }
}

// 凸包を求めるアンドリューのアルゴリズム
Polygon AndrewScan(Polygon pg) {
  Polygon upper, lower;

  bool changeFlag = true;

  if (pg.size() < 3) {
    return pg;
  }

  // 点の集合をx軸について, 昇順に並び替える
  while (changeFlag) {
    changeFlag = false;

    for (unsigned int i = 0; i < pg.size() - 1; i++) {
      if (pg[i + 1] <= pg[i]) {
        swap(pg[i + 1], pg[i]);
        changeFlag = true;
      }
    }
  }

  // -------------------------
  // ----- 凸包の上部を作成 -----
  // -------------------------

  // 初期値として, 2点を入れておく
  upper.push_back(pg[0]);
  upper.push_back(pg[1]);

  setMinPoint(pg[0], 0);
  setMinPoint(pg[1], 1);

  for (int i = 2; i < pg.size(); i++) {
    while (ccw(upper[upper.size() - 2], upper[upper.size() - 1], pg[i]) ==
           COUNTER_CLOCKWISE) {
      if (upper.size() > 1) {
        // 追加する点が, 直前の2点が作るベクトルに対して,
        // 反時計回りの方向にあるなら, 最後の点を削除する
        upper.pop_back();
      } else {
        break;
      }
    }

    upper.push_back(pg[i]);
    setMinPoint(pg[i], i);
  }

  // -------------------------
  // ----- 凸包の下部を作成 -----
  // -------------------------
  lower.push_back(pg[pg.size() - 1]);
  lower.push_back(pg[pg.size() - 2]);

  setMinPoint(pg[pg.size() - 1], pg.size() - 1);
  setMinPoint(pg[pg.size() - 2], pg.size() - 2);

  for (int i = pg.size() - 3; i >= 0; i--) {
    while (ccw(lower[lower.size() - 2], lower[lower.size() - 1], pg[i]) ==
           COUNTER_CLOCKWISE) {
      if (lower.size() > 1) {
        // 追加する点が, 直前の2点が作るベクトルに対して,
        // 反時計回りの方向にあるなら, 最後の点を削除する
        lower.pop_back();
      } else {
        break;
      }
    }

    lower.push_back(pg[i]);
    setMinPoint(pg[i], i);
  }

  // 時計回りになるように凸包の点の列を生成
  reverse(lower.begin(), lower.end());
  for (int i = upper.size() - 2; i >= 1; i--) {
    // 凸包の下部の点と重ならないように追加する
    lower.push_back(upper[i]);
  }

  for (int i = 0; i < lower.size(); i++) {
    if (minPoint.p == lower[i]) {
      // 最下点の要素のインデックスを求める
      minPoint.index = i;
      break;
    }
  }

  return lower;
}