极角排序求凸包 水平排序求凸包
极角排序
struct Point { double x, y; Point () {} Point (double _x, double _y) : x(_x), y(_y) {} Point operator + (const Point &a) const { return Point(x + a.x, y + a.y); } // 叉积=0是指两向量平行(重合) Point operator - (const Point &a) const { return Point(x - a.x, y - a.y); } double operator ^ (const Point &a) const { return x * a.y - y * a.x; } // 叉积 double operator * (const Point &a) const { return x * a.x + y * a.y; } // 点积 // 定义给map set 之类用的.. 不要用极角 可能会出错 bool operator < (const Point &a) const { if (x != a.x) return x < a.x; return y < a.y; } }; double GetCross(Point st, Point ed1, Point ed2) { return (ed1 - st) ^ (ed2 - st); } // 叉积极角排序 // 直接把原点当作 极点 进行 极角排序. bool cmp_j_j(const Point &A, const Point &B) { if ((A ^ B) != 0.0) return (A ^ B) > 0.0; if (A.x != B.x) return A.x < B.x; return A.y < B.y; } // 叉积极角排序. // 以Qcmppt为起点 做极角排序. Point Qcmppt; bool cmp_j_j_j(const Point &A, const Point &B) { int m = (A-Qcmppt) ^ (B-Qcmppt); if (m != 0.0) return m > 0.0; if (A.x != B.x) return A.x < B.x; return false; } // atan2 极角排序 // atan2 赛高 听说速度快些 但是精度比叉积差些 听说,.,, 未实践 bool cmp_o_o(const Point &A, const Point &B) { if (atan2(A.y, A.x) != atan2(B.y, B.x)) return atan2(A.y, A.x) < atan2(B.y, B.x); if (A.x != B.x) return A.x < B.x; return A.y < B.y; } // --------------------------------------------------------- // 凸包 极角排序 不能用于共线点 // 要把第一个点(最左下角的点)放在最前面 而且sort的时候不包含进去. // 该点是起点 for (i=1; i<=n; ++i) { scanf("%lf%lf", &pt[i].x, &pt[i].y); pt[i].flag = false; if (pt[i].y < pt[1].y) swap(pt[i], pt[1]); else if (pt[i].y == pt[1].y && pt[i].x < pt[1].x) swap(pt[i], pt[1]); } Qcmppt = pt[1]; // Qcmppt 全局变量 sort(pt+2, pt+1+m+n, cmp_j_j_j); // 排序方法也可以用 atan2 排序 cmp_o_o() head = 0; for (i=1; i<=n; ++i) { while (head>1 && GetCross(pt[st[head-1]], pt[st[head]], pt[i]) <= 0.0) head--; st[++head] = i; } // head 就是点的个数
水平排序求凸包
struct Point { double x, y; Point () {} Point (double _x, double _y) : x(_x), y(_y) {} Point operator + (const Point &a) const { return Point(x + a.x, y + a.y); } // 叉积=0是指两向量平行(重合) Point operator - (const Point &a) const { return Point(x - a.x, y - a.y); } double operator ^ (const Point &a) const { return x * a.y - y * a.x; } // 叉积 double operator * (const Point &a) const { return x * a.x + y * a.y; } // 点积 // 定义给map set 之类用的.. 不要用极角 可能会出错 bool operator < (const Point &a) const { if (x != a.x) return x < a.x; return y < a.y; } }; double GetCross(Point st, Point ed1, Point ed2) { return (ed1 - st) ^ (ed2 - st); } // 凸包 水平排序 允许有重点 // 点从1到n sort(pt+1, pt+n+1, cmp_s_p); head = 0; for (i=1; i<=n; ++i) { // 如果 不希望 有"三点共线", 重点 把 下面的 两个 < 都改成 <= while (head>1 && GetCross(pt[st[head-1]], pt[st[head]], pt[i]) < 0.0) head--; st[++head] = i; } int t = head; for (i=n-1; i>=1; --i) { // 注意是n-1 while (head>=t && GetCross(pt[st[head-1]], pt[st[head]], pt[i]) < 0.0) head--; // 貌似head>=t 不然wa....原理嘛...不是很懂. st[++head] = i; } // 答案会把起点包含2次 所以看情况 head减1