結果
問題 |
No.3154 convex polygon judge
|
ユーザー |
![]() |
提出日時 | 2025-05-20 21:46:50 |
言語 | C++23 (gcc 13.3.0 + boost 1.87.0) |
結果 |
AC
|
実行時間 | 143 ms / 2,000 ms |
コード長 | 16,642 bytes |
コンパイル時間 | 3,720 ms |
コンパイル使用メモリ | 301,696 KB |
実行使用メモリ | 22,276 KB |
最終ジャッジ日時 | 2025-05-20 21:46:57 |
合計ジャッジ時間 | 6,173 ms |
ジャッジサーバーID (参考情報) |
judge4 / judge2 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
sample | AC * 3 |
other | AC * 44 |
ソースコード
#include <bits/stdc++.h> using namespace std; using ld = long double; #undef long #define long long long #define ll long #define vec vector #define rep(i, n) for (long i = 0; i < n; i++) #define all(a) begin(a), end(a) #define sz(a) (int)(a).size() template <typename T> bool chmin(T &x, T y) { if (y < x) { x = y; return true; } return false; } template <typename T> bool chmax(T &x, T y) { if (x < y) { x = y; return true; } return false; } template <typename T> ostream &operator<<(ostream &os, vector<T> a) { const int n = a.size(); rep(i, n) { os << a[i]; if (i + 1 != n) os << " "; } return os; } using R = ld; using point = std::complex<R>; using arrow = point; const R EPS(1e-10), PI(acosl(-1)); inline bool eq(const R &a, const R &b) { return abs(b - a) < EPS; } inline bool same_point(const point &a, const point &b) { return abs(b - a) < EPS; } /* sign of x -1: x < 0 0: x == 0 1: x > 0 */ inline int sgn(const R &x) { return abs(x) < EPS ? 0 : (x < 0 ? -1 : 1); } /* sign of (a-b) -1: a < b 0: a == b 1: a > b */ inline int compare(const R &a, const R &b) { return eq(a, b) ? 0 : a < b ? -1 : 1; } std::istream &operator>>(std::istream &is, point &p) { R a, b; is >> a >> b; p = point(a, b); return is; } std::ostream &operator<<(std::ostream &os, point &p) { return os << '(' << p.real() << ", " << p.imag() << ')'; } // rotate point 'p' for counter clockwise direction point rotate(const point &p, const R &theta) { return point(cosl(theta) * p.real() - sinl(theta) * p.imag(), sinl(theta) * p.real() + cosl(theta) * p.imag()); } R radian_to_degree(const R &r) { return (r * 180.0 / PI); } R degree_to_radian(const R &d) { return (d * PI / 180.0); } // get angle a-b-c (<pi) R get_angle(const point &a, const point &b, const point &c) { const point v(a - b), w(c - b); R theta = abs(atan2l(w.imag(), w.real()) - atan2l(v.imag(), v.real())); return std::min(theta, 2 * PI - theta); } namespace std { bool operator<(const point &a, const point &b) { return a.real() != b.real() ? a.real() < b.real() : a.imag() < b.imag(); } } // namespace std struct segment; struct line { point a, b; line() = default; line(const point &a, const point &b) : a(a), b(b) {} // Ax + By + C = 0 line(const R &A, const R &B, const R &C) { if (eq(A, 0)) { assert(!eq(B, 0)); a = point(0, -C / B), b = point(1, -(A + C) / B); } else { a = point(-C / A, 0), b = point(-(B + C) / A, 1); } } explicit line(const segment &seg); friend std::ostream &operator<<(std::ostream &os, const line &ln) { return os << '(' << ln.a << " -- " << ln.b << ')'; } friend std::istream &operator>>(std::istream &is, line &a) { return is >> a.a >> a.b; } }; struct segment { point a, b; segment() = default; segment(const point &a, const point &b) : a(a), b(b) {} explicit segment(const line &ln) : a(ln.a), b(ln.b) {} friend std::ostream &operator<<(std::ostream &os, const segment &seg) { return os << '[' << seg.a << " -- " << seg.b << ']'; } friend std::istream &operator>>(std::istream &is, segment &a) { return is >> a.a >> a.b; } }; line::line(const segment &seg) : a(seg.a), b(seg.b) {} struct circle { point center; R radius; circle() = default; circle(const point ¢er, const R &radius) : center(center), radius(radius) {} friend std::ostream &operator<<(std::ostream &os, const circle &c) { return os << '(' << c.center << ", " << c.radius << ')'; } friend std::istream &operator>>(std::istream &is, circle &c) { return is >> c.center >> c.radius; } }; using points = std::vector<point>; using polygon = std::vector<point>; using segments = std::vector<segment>; using lines = std::vector<line>; using circles = std::vector<circle>; // 内積 R cross(const point &a, const point &b) { return real(a) * imag(b) - imag(a) * real(b); } // 外積 R dot(const point &a, const point &b) { return real(a) * real(b) + imag(a) * imag(b); } // 点 a,b から見て c がどの位置にいるか enum CCW { ONLINE_FRONT = -2, // a,b,c が一直線上 CLOCKWISE = -1, // c が a,b から時計回り側 ON_SEGMENT = 0, // a,c,b が一直線上 COUNTER_CLOCKWISE = 1, // c が a,b から反時計回り側 ONLINE_BACK = 2, // c,a,b が一直線上 }; int ccw(const point &a, point b, point c) { b -= a, c -= a; const R crs_b_c = cross(b, c); if (crs_b_c > EPS) return CCW::COUNTER_CLOCKWISE; if (crs_b_c < -EPS) return CCW::CLOCKWISE; if (dot(b, c) < -EPS) return CCW::ONLINE_BACK; if (norm(b) + EPS < norm(c)) return CCW::ONLINE_FRONT; return CCW::ON_SEGMENT; } bool parallel(const arrow &a, const arrow &b) { return eq(cross(a, b), R(0)); } bool parallel(const line &a, const line &b) { return parallel(a.b - a.a, b.b - b.a); } bool parallel(const line &a, const segment &b) { return parallel(a.b - a.a, b.b - b.a); } bool parallel(const segment &a, const line &b) { return parallel(a.b - a.a, b.b - b.a); } bool parallel(const segment &a, const segment &b) { return parallel(a.b - a.a, b.b - b.a); } bool orthogonal(const arrow &a, const arrow &b) { return eq(dot(a, b), R(0)); } bool orthogonal(const line &a, const line &b) { return orthogonal(a.b - a.a, b.b - b.a); } bool orthogonal(const line &a, const segment &b) { return orthogonal(a.b - a.a, b.b - b.a); } bool orthogonal(const segment &a, const line &b) { return orthogonal(a.b - a.a, b.b - b.a); } bool orthogonal(const segment &a, const segment &b) { return orthogonal(a.b - a.a, b.b - b.a); } point projection(const line &l, const point &p) { return l.a + (l.a - l.b) * dot(p - l.a, l.a - l.b) / norm(l.a - l.b); } point projection(const segment &s, const point &p) { return projection(line(s), p); } point reflection(const line &l, const point &p) { return projection(l, p) * R(2) - p; } point reflection(const segment &s, const point &p) { return projection(line(s), p); } R distance(const point &p, const point &q); R distance(const line &l, const point &p); int number_of_common_tangents(const circle &c1, const circle &c2) { const R r1 = std::min(c1.radius, c2.radius), r2 = std::max(c1.radius, c2.radius), d = distance(c1.center, c2.center); int com = compare(r1 + r2, d); return com == 1 ? compare(d + r1, r2) + 1 : 3 - com; } // number of common points (-1: infinite) int intersect(const line &l, const point &p) { return int(abs(ccw(l.a, l.b, p)) != 1); } int intersect(const point &p, const line &l) { return intersect(l, p); } int intersect(const line &l, const line &m) { if (intersect(l, m.a) && intersect(l, m.b)) return -1; return int(!parallel(l, m)); } int intersect(const segment &s, const point &p) { return int(ccw(s.a, s.b, p) == CCW::ON_SEGMENT); } int intersect(const point &p, const segment &s) { return intersect(s, p); } int intersect(const line &l, const segment &s) { if (intersect(l, s.a) && intersect(l, s.b)) return -1; return ccw(l.a, l.b, s.a) * ccw(l.a, l.b, s.b) != 1; } int intersect(const segment &s, const line &l) { return intersect(l, s); } int intersect(const circle &c, const line &l) { R d = c.radius - distance(l, c.center); return abs(d) < EPS ? 1 : d > 0. ? 2 : 0; } int intersect(const line &l, const circle &c) { return intersect(c, l); } int intersect(const circle &c, const point &p) { return int(eq(c.radius, distance(c.center, p))); } int intersect(const point &p, const circle &c) { return intersect(c, p); } int intersect(const segment &s, const segment &t) { if (same_point(s.a, s.b)) return intersect(t, s.a); if (intersect(line(s), t.a) && intersect(line(s), t.b) && std::max(std::min(s.a, s.b), std::min(t.a, t.b)) < std::min(std::max(s.a, s.b), std::max(t.a, t.b))) return -1; return int(ccw(s.a, s.b, t.a) * ccw(s.a, s.b, t.b) <= 0 && ccw(t.a, t.b, s.a) * ccw(t.a, t.b, s.b) <= 0); } int intersect(const circle &c, const segment &s) { const point h = projection(s, c.center); const int c0 = compare(distance(h, c.center), c.radius); if (c0 == 1) return 0; if (c0 == 0) return intersect(s, h); const int c1 = compare(distance(c.center, s.a), c.radius), c2 = compare(distance(c.center, s.b), c.radius); if (std::min(c1, c2) == -1) return int(std::max(c1, c2) >= 0); return intersect(s, h) ? 2 : 0; } int intersect(const segment &s, const circle &c) { return intersect(c, s); } int intersect(const circle &c1, const circle &c2) { return 2 - abs(2 - number_of_common_tangents(c1, c2)); } // distance of two shapes R distance(const point &a, const point &b) { return abs(a - b); } R distance(const line &l, const point &p) { return distance(p, projection(l, p)); } R distance(const point &p, const line &l) { return distance(l, p); } R distance(const line &l, const line &m) { return parallel(l, m) ? distance(l, m.a) : 0; } R distance(const segment &s, const point &p) { const point r = projection(s, p); return intersect(s, r) ? distance(r, p) : std::min(distance(s.a, p), distance(s.b, p)); } R distance(const point &p, const segment &s) { return distance(s, p); } R distance(const segment &a, const segment &b) { if (intersect(a, b)) return R(0); return std::min({distance(a, b.a), distance(a, b.b), distance(b, a.a), distance(b, a.b)}); } R distance(const line &l, const segment &s) { if (intersect(l, s)) return 0; return std::min(distance(l, s.a), distance(l, s.b)); } R distance(const segment &s, const line &l) { return distance(l, s); } R distance(const circle &c, const point &p) { return abs(distance(c.center, p) - c.radius); } R distance(const point &p, const circle &c) { return distance(c, p); } R distance(const circle &c, const line &l) { return std::max(R(0), distance(l, c.center) - c.radius); } R distance(const line &l, const circle &c) { return distance(c, l); } R distance(const circle &c1, const circle &c2) { const R d = distance(c1.center, c2.center); if (d > c1.radius + c2.radius) return d - c1.radius - c2.radius; if (d < abs(c1.radius - c2.radius)) return abs(c1.radius - c2.radius) - d; return R(0); } R distance(const circle &c, const segment &s) { const point p = projection(s, c.center); const R dist_min = intersect(s, p) ? distance(c.center, p) : std::min(distance(c.center, s.a), distance(c.center, s.b)); if (dist_min > c.radius) return dist_min - c.radius; const R dist_max = std::max(distance(c.center, s.a), distance(c.center, s.b)); return dist_max < c.radius ? c.radius - dist_max : R(0); } R distance(const segment &s, const circle &c) { return distance(c, s); } point crosspoint(const line &l, const line &m) { R A = cross(l.b - l.a, m.b - m.a); R B = cross(l.b - l.a, l.b - m.a); if (eq(A, 0.)) return m.a; return m.a + (m.b - m.a) * B / A; } point crosspoint(const segment &s, const segment &t) { return crosspoint(line(s), line(t)); } point crosspoint(const segment &s, const line &l) { return crosspoint(line(s), l); } point crosspoint(const line &l, const segment &s) { return crosspoint(l, line(s)); } points crosspoints(const circle &c, const line &l) { const point pr = projection(l, c.center); const R square = c.radius * c.radius - norm(pr - c.center); switch (sgn(square)) { case 0: return points{pr}; case -1: return points(0); } const arrow v = (l.b - l.a) / abs(l.b - l.a) * sqrtl(square); return points{pr - v, pr + v}; } points crosspoints(const line &l, const circle &c) { return crosspoints(c, l); } points crosspoints(const circle &c, const segment &s) { points ret; for (const auto &pt : crosspoints(c, line(s))) if (intersect(s, pt)) ret.push_back(pt); return ret; } points crosspoints(const segment &s, const circle &c) { return crosspoints(c, s); } points crosspoints(const circle &c1, const circle &c2) { R d = abs(c1.center - c2.center); if (compare(d, c1.radius + c2.radius) == 1) return points(0); if (compare(d, abs(c1.radius - c2.radius)) == -1) return points(0); bool one_crosspoint = false; if (eq(d, c1.radius + c2.radius) || eq(d, abs(c1.radius - c2.radius))) one_crosspoint = true; const R alpha = acosl((c1.radius * c1.radius + d * d - c2.radius * c2.radius) / (2 * c1.radius * d)); // cosine theorem const R beta = std::arg(c2.center - c1.center); if (one_crosspoint) return points{c1.center + std::polar(c1.radius, beta + alpha)}; return points{c1.center + std::polar(c1.radius, beta + alpha), c1.center + std::polar(c1.radius, beta - alpha)}; } points tangent_points(const circle &c, const point &p) { const R square = norm(c.center - p) - c.radius * c.radius; switch (sgn(square)) { case 0: return points{p}; case -1: return points{}; } return crosspoints(c, circle(p, sqrtl(square))); } // common tangents of two circles lines tangents(circle c1, circle c2) { lines ret; if (c1.radius < c2.radius) std::swap(c1, c2); const R g = distance(c1.center, c2.center); if (!sgn(g)) return ret; const arrow u = (c2.center - c1.center) / g; const arrow v = rotate(u, PI * 0.5); for (const int &s : {-1, 1}) { const R h = (c1.radius + s * c2.radius) / g; if (eq(1 - h * h, 0)) { ret.emplace_back(c1.center + u * c1.radius, c1.center + (u + v) * c1.radius); } else if (1 - h * h > 0) { const point uu = u * h, vv = v * sqrtl(1 - h * h); ret.emplace_back(c1.center + (uu + vv) * c1.radius, c2.center - (uu + vv) * c2.radius * R(s)); ret.emplace_back(c1.center + (uu - vv) * c1.radius, c2.center - (uu - vv) * c2.radius * R(s)); } } return ret; } bool is_convex(const polygon &p, bool pi_is_ok = true) { int n = (int)p.size(); if (pi_is_ok) { for (int i = 0; i < n; i++) if (ccw(p[i], p[(i + 1) % n], p[(i + 2) % n]) == -1) return false; } else { for (int i = 0; i < n; i++) if (ccw(p[i], p[(i + 1) % n], p[(i + 2) % n]) != 1) return false; } return true; } polygon convex_hull(polygon &p, bool vertices_on_edge_remain = true) { int n = (int)p.size(), k = 0; if (n <= 2) return p; sort(p.begin(), p.end()); points ch(2 * n); if (vertices_on_edge_remain) { for (int i = 0; i < n; ch[k++] = p[i++]) while (k >= 2 && ccw(ch[k - 2], ch[k - 1], p[i]) == -1) --k; for (int i = n - 2, t = k + 1; i >= 0; ch[k++] = p[i--]) while (k >= t && ccw(ch[k - 2], ch[k - 1], p[i]) == -1) --k; } else { for (int i = 0; i < n; ch[k++] = p[i++]) while (k >= 2 && ccw(ch[k - 2], ch[k - 1], p[i]) != 1) --k; for (int i = n - 2, t = k + 1; i >= 0; ch[k++] = p[i--]) while (k >= t && ccw(ch[k - 2], ch[k - 1], p[i]) != 1) --k; } ch.resize(k - 1); return ch; } // 凸多角形 U を直線 a-b で切断し、左側に残る部分多角形(左半平面)を返す // (i.e. forall p \in (returned polygon), ccw(a, b, p) != -1) polygon convex_cut(const polygon &U, const point &a, const point &b) { polygon ret; const line l(a, b); for (int i = 0; i < int(U.size()); i++) { const point &now = U[i], &nxt = U[(i + 1) % int(U.size())]; if (ccw(l.a, l.b, now) != -1) ret.push_back(now); if (ccw(l.a, l.b, now) * ccw(l.a, l.b, nxt) == -1) ret.push_back(crosspoint(line(now, nxt), l)); } return ret; } void solve() { int n; cin >> n; vec<point> a(n); rep(i, n) { ld x, y; cin >> x >> y; a[i] = {x, y}; } auto res = convex_hull(a, false); cout << (sz(res) == n ? "Yes" : "No") << endl; } int main() { cin.tie(0)->sync_with_stdio(0), cout.tie(0); cout << fixed << setprecision(20); int t = 1; // cin >> t; while (t--) solve(); }