等价于对于折线每个端点,都能找到一条直线使得所有之前和之后的点分立两侧,在每个点处极角排序 + 双指针即可。
#include <stdio.h> #include <algorithm> typedef long long ll; const int MAXN = 1010; int n, tot; struct point{ ll x, y; int id; }; point a[MAXN], b[MAXN]; point operator - (point p, point q) { point res = p; res.x -= q.x, res.y -= q.y; return res; } ll operator * (point p, point q) { return p.x * q.y - q.x * p.y; } int quad(point p) { if (p. x == 0) { if (p.y > 0) return 3; else return 7; } else if (p.x > 0) { if (p.y > 0) return 2; else if (p.y == 0) return 1; else return 8; } else { if (p.y > 0) return 4; else if (p.y == 0) return 5; else return 6; } } int main() { scanf("%d", &n); for (int i = 1; i <= n; ++i) { scanf("%lld%lld", &a[i].x, &a[i].y); a[i].id = i; } for (int i = 1; i <= n; ++i) { tot = 0; for (int j = 1; j <= n; ++j) { if (i == j) continue; b[tot++] = a[j] - a[i]; } std::sort(b, b + tot, [](point p, point q){return quad(p) == quad(q) ? p * q > 0 : quad(p) < quad(q);}); int cnt1 = 0, cnt2 = 0;//cnt1 是 id 比 i 小的点的个数,cnt2 是 id 比 i 大的点的个数 bool flag = false; for (int l = 0, r = -1; l < tot; ) { while (r + 1 < l + tot && b[l] * b[(r + 1) % tot] >= 0) { r++; if (b[r % tot].id < i) cnt1++; else cnt2++; } if ((cnt1 == i - 1 && !cnt2) || (cnt2 == n - i && !cnt1)) { flag = true; break; } if (b[l].id < i) cnt1--; else cnt2--; l++; } if (!flag) { printf("Impossible"); return 0; } } printf("Possible"); return 0; }