资料
http://hivemined.ir/wp-content/uploads/2012/04/convexHull.pdf
http://en.literateprograms.org/Quickhull_%28Python%2C_arrays%29
#include #include #include #include #include #include #include #include #include using namespace std; #define MIN(a, b) ((a) < (b) ? (a) : (b)) #define MAX(a, b) ((a) > (b) ? (a) : (b)) #define REP(i, s, t) for(int (i)=(s);(i)<=(t);++(i)) #define UREP(i, s, t) for(int (i)=(s);(i)>=(t);--(i)) const double eps = 1e-5; const int INF = 0x7FFFFFFF; struct Point { double x, y; Point(){}; Point(double x, double y):x(x),y(y){}; }; typedef Point Vector; Vector operator - (Point A, Point B) { return Vector(A.x-B.x, A.y - B.y); } Vector operator + (Point A, Point B) { return Vector(A.x+B.x, A.y+B.y); } Vector operator * (Vector A, double p) { return Vector(A.x*p, A.y*p); } Vector operator / (Vector A, double p) { return Vector(A.x/p, A.y/p); } // 用以避免精度误差 int dcmp(double x) { if (fabs(x) < eps) return 0; else return x < 0 ? -1 : 1; } bool operator == (const Point& a, const Point& b) { if (dcmp(a.x - b.x) == 0 && dcmp(a.y - b.y) == 0) return true; return false; } // 需要更高精度,使用dcmp bool operator < (const Point& a, const Point& b) { return a.x < b.x || (a.x == b.x && a.y < b.y); } // 内积 double Dot(Vector A, Vector B) { return A.x*B.x + A.y*B.y; } // 外积 axb // theta 为 a 逆时针转到 b 所需角度 // theta < pi : axb>0 // theta > pi : axb<0 // theta = pi : axb=0 double Cross(Vector A, Vector B) { return A.x*B.y-A.y*B.x; } // 模 double Length(Vector A) { return sqrt(Dot(A, A)); } // ccw = (B-A) X (C-A) // ret > 0 : C 在AB左侧 // ret < 0 : C 在AB右侧 #define ccw(A, B, C) (Cross((B)-(A),(C)-(A))) // 点到线段距离 double DistanceToSegment(Point P, Point A, Point B) { if (A == B) return Length(P - A); Vector v1 = B - A, v2 = P - A, v3 = P - B; if (dcmp(Dot(v1, v2)) < 0) // 投影在A的外侧 return Length(v2); // 投影在B的外侧 else if (dcmp(Dot(v1, v3)) > 0) return Length(v3); else return fabs(Cross(v1, v2)) / Length(v1); } const int mod = 203;//10007 const int left_bound = 10, up_bound = 10; vector generate_points(int n) { vector ret; srand(time(0)); //srand(4); for (int i=0;i left_bound && y > up_bound) break; } ret.push_back(Point(x, y)); } return ret; } void print(vector v) { for (int i=0;i v, int s, int t) { for (int i=s;i<=t;++i) printf("(%d %d) ", (int)v[i].x, (int)v[i].y);printf("\n"); } void fprint(vector& v, int s, int t, FILE* fp) { for (int i=s;i<=t;++i) fprintf(fp, "%d %d\n", (int)v[i].x, (int)v[i].y); } /* v 是要求凸包的顶点序列 * a 是 v 中最左边的点,b 是 v 中最右边的点 * 函数返回 v 中位于 向量 ab 左边的点集的凸包,以逆时针排列。 */ vector qhull(vector& v, Point& a, Point& b) { vector ret; int sz = v.size(); int id = -1; double max_dist = 0; for (int i=0;i 0) { double tmp = DistanceToSegment(pt, a, b); if (dcmp(tmp - max_dist) > 0) { max_dist = tmp; id = i; } } } ret.push_back(b); if (id != -1) { Point c = v[id]; vector lv, rv; for (int i=0;i 0) lv.push_back(pt); if (ccw(c, b, pt) > 0) rv.push_back(pt); } //cout << "lv: ";print(lv); //cout << "rv: ";print(rv); vector left = qhull(lv, a, c); vector right = qhull(rv, c, b); if (right.size() > 2) { ret.insert(ret.end(), right.begin()+1, right.end()-1); } ret.push_back(c); if (left.size() > 2) ret.insert(ret.end(), left.begin()+1, left.end()-1); } ret.push_back(a); return ret; } int main() { //freopen("input.in", "r", stdin); vector v = generate_points(10); sort(v.begin(), v.end()); Point a = v[0];Point b = v[v.size()-1]; vector upper_half = qhull(v, a, b); vector lower_half = qhull(v, b, a); //print(upper_half); //print(lower_half); #if 1 //print(upper_half); //print(lower_half, 1, lower_half.size()-2); FILE *fp = fopen("D:\\CTdeWorkShop\\acm\\LRJ Guide\\output.txt", "w"); fprintf(fp, "%d\n", v.size()); fprint(v, 0, v.size()-1, fp); fprintf(fp, "%d\n", upper_half.size()+lower_half.size()-2); //fprintf(fp, "%d\n", upper_half.size()); fprint(upper_half, 0, upper_half.size()-1, fp); //fprintf(fp, "%d\n", lower_half.size()); //fprint(lower_half, 0, lower_half.size()-1, fp); fprint(lower_half, 1, lower_half.size()-2, fp); //fprintf(fp, "2\n"); //fprintf(fp, "%d %d\n%d %d\n", (int)a.x, (int)a.y, (int)b.x, (int)b.y); fclose(fp); #endif return 0; }