QuickHull 快速凸包算法

资料

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;
}


你可能感兴趣的:(ACM.算法笔记)