第十六章 计算几何模版
2018-01-01 03:02
363 查看
模版
#define EPS (1e-10) #define equals(a,b) (fabs((a) - (b)) < EPS) // 点类 class Point { public : double x, y; Point() {}; Point(double x, double y) :x(x), y(y) {} Point operator + (Point p) { return Point(x + p.x, y + p.y); } Point operator - (Point p) { return Point(x - p.x, y - p.y); } Point operator * (double a) { return Point(x * a, y * a); } Point operator / (double a) { return Point(x / a, y / a); } bool operator < (const Point &p) const { return x != p.x ? x < p.x : y < p.y; } bool operator == (const Point &p) const { return fabs(x - p.x) < EPS && fabs(y - p.y) < EPS; } }; // 线段类 class Segment { public: Point p1, p2; Segment() {}; Segment(Point p1, Point p2) :p1(p1), p2(p2) {}; }; // 圆类 class Circle { public: Point c; double r; Circle() {}; Circle(Point c, double r) :c(c), r(r) {} }; // 定义向量 typedef Point Vector; // 定义直线 typedef Segment Line; // 定义多边形 typedef vector<Point> Polygon; /***************************点、向量****************************/ double norm(Point p) { return p.x * p.x + p.y * p.y; } double abs(Point p) { return sqrt(norm(p)); } // 向量的内积 double dot(Point a, Point b) { return a.x * b.x + a.y * b.y; } // 向量的外积 double cross(Point a, Point b) { return a.x * b.y - a.y * b.x; } // 向量a,b是否正交 <==> 内积为0 bool isOrthogonal(Vector a, Vector b) { return equals(dot(a, b), 0.0); } bool isOrthogonal(Point a1, Point a2, Point b1, Point b2) { return equals(dot(a1 - a2, b1 - b2), 0.0); } // 向量a,b是否平行 <==> 外积为0 bool isParallel(Vector a, Vector b) { return equals(cross(a, b), 0.0); } bool isParallel(Point a1, Point a2, Point b1, Point b2) { return equals(cross(a1 - a2, b1 - b2), 0.0); } // 点p在线段s上的投影 Point project(Segment s, Point p) { Vector base = s.p2 - s.p1; double r = dot(p - s.p1, base) / norm(base); return s.p1 + base * r ; } //以线段s为对称轴与点p成线对称的点 Point reflect(Segment s, Point p) { return p + (project(s, p) - p) * 2.0; } // 点a到点b的距离 double getDistance(Point a, Point b) { return abs(a - b); } // 线段l和点p的距离 double getDistanceLP(Line l, Point p) { return abs( cross(l.p2 - l.p1, p - l.p1) / abs(l.p2 - l.p1) ); } // 线段s与点p的距离 double getDistanceSP(Segment s, Point p) { if (dot(s.p2 - s.p1, p - s.p1) < 0.0) return abs(p - s.p1); if (dot(s.p1 - s.p2, p - s.p2) < 0.0) return abs(p - s.p2); return getDistanceLP(s, p); } /*************************线段********************************/ // 线段s1,s2是否正交 <==> 内积为0 bool isOrthogonal(Segment s1, Segment s2) { return equals(dot(s1.p2 - s1.p1, s2.p2 - s2.p1), 0.0); } // 线段s1,s2是否平行 <==> 外积为0 bool isParallel(Segment s1, Segment s2) { return equals(cross(s1.p2 - s1.p1, s2.p2 - s2.p1), 0.0); } // 逆时针方向ccw(Counter-Clockwise) static const int COUNTER_CLOCKWISE = 1; static const int CLOCKWISE = -1; static const int ONLINE_BACK = 2; static const int ONLINE_FRONT = -2; static const int ON_SEGMENT = 0; int ccw(Point p0, Point p1, Point p2) { Vector a = p1 - p0; Vector b = p2 - p0; if (cross(a, b) > EPS) return COUNTER_CLOCKWISE; if (cross(a, b) < -EPS) return CLOCKWISE; if (dot(a, b) < -EPS) return ONLINE_BACK; if (norm(a) < norm(b)) return ONLINE_FRONT; return ON_SEGMENT; } // 判断线段p1p2和线段p3p4是否相交 bool intersect(Point p1, Point p2, Point p3, Point p4) { return (ccw(p1, p2, p3) * ccw(p1, p2, p4) <= 0 && ccw(p3, p4, p1) * ccw(p3, p4, p2) <= 0); } //判断线段s1和s2是否相交 bool intersect(Segment s1, Segment s2) { return intersect(s1.p1, s1.p2, s2.p1, s2.p2); } // 线段s1和线段s2的距离 double getDistance(Segment s1, Segment s2) { // 相交 if (intersect(s1, s2)) return 0.0; return min(min(getDistanceSP(s1, s2.p1), getDistanceSP(s1, s2.p2)), min(getDistanceSP(s2, s1.p1), getDistanceSP(s2, s1.p2))); } // 线段s1与线段s2的交点 Point getCrossPoint(Segment s1, Segment s2) { Vector base = s2.p2 - s2.p1; double d1 = abs(cross(base, s1.p1 - s2.p1)); double d2 = abs(cross(base, s1.p2 - s2.p1)); double t = d1 / (d1 + d2); return s1.p1 + (s1.p2 - s1.p1) * t; } /***************************圆****************************/ // 圆c和直线l的交点 pair<Point, Point> getCrossPoints(Circle c, Line l) { Vector pr = project(l, c.c); Vector e = (l.p2 - l.p1) / abs(l.p2 - l.p1); double base = sqrt(c.r * c.r - norm(pr - c.c)); return make_pair(pr + e * base, pr - e * base); } // 圆c1和圆c2的交点 double arg(Vector p) { return atan2(p.y, p.x); } Vector polar(double a, double r) { return Point(cos(r) * a, sin(r) * a); } pair<Point, Point> getCrossPoints(Circle c1, Circle c2) { double d = abs(c1.c - c2.c); double a = acos((c1.r * c1.r + d * d - c2.r * c2.r) / (2 * c1.r * d)); double t = arg(c2.c - c1.c); return make_pair(c1.c + polar(c1.r, t + a), c1.c + polar(c1.r, t - a)); } /***************************多边形****************************/ // 点的内包 /* IN 2 ON 1 OUT 0 */ int contains(Polygon g, Point p) { int n = g.size(); bool x = false; for (int i = 0; i < n; i++) { Point a = g[i] - p, b = g[(i + 1) % n] - p; if (abs(cross(a, b)) < EPS && dot(a, b) < EPS) return 1; if (a.y > b.y) swap(a, b); if (a.y < EPS && EPS < b.y && cross(a, b) > EPS) x = !x; } return (x ? 2 : 0); } int cmp(Point A, P 12460 oint B) //竖直排序 { return (A.y<B.y || (A.y == B.y&&A.x<B.x)); } // 凸包 Polygon andrewScan(Polygon s) { Polygon u, l; int len = s.size(); if (len < 3) return s; // 以x,y为基准升序排序 sort(s.begin(), s.end()); // 将x值最小的两个点添加到u u.push_back(s[0]); u.push_back(s[1]); // 将x值最大的两个点添加到l l.push_back(s[len - 1]); l.push_back(s[len - 2]); // 构建凸包上部 for (int i = 2; i < len; i++) { for (int j = u.size(); j >= 2 && ccw(u[j - 2], u[j - 1], s[i]) >= 0; j--) { u.pop_back(); } u.push_back(s[i]); } // 构建凸包下部 for (int i = len - 3; i >= 0; i--) { for (int j = l.size(); j >= 2 && ccw(l[j - 2], l[j - 1], s[i]) >= 0; j--) { l.pop_back(); } l.push_back(s[i]); } reverse(l.begin(), l.end()); for (int i = u.size() - 2; i >= 1; i--) l.push_back(u[i]); return l; }
题目链接
CGL_2_A:Parallel/Orthogonal求直线s1、s2的关系。若是平行则输出2,若相交则输出1,其他输出0
Point p1, p2, p3, p4; int n; scanf("%d", &n); while (n--) { scanf("%lf %lf %lf %lf %lf %lf %lf %lf", &p1.x, &p1.y, &p2.x, &p2.y, &p3.x, &p3.y, &p4.x, &p4.y); // 平行 if (isParallel(p1, p2, p3, p4)) printf("2\n"); // 正交 else if (isOrthogonal(p1, p2, p3, p4)) printf("1\n"); else printf("0\n"); }
CGL_1_A:Projection
输出各点在直线p1p2的投影
Segment s; Point p, ans; int n; scanf("%lf %lf %lf %lf", &s.p1.x, &s.p1.y, &s.p2.x, &s.p2.y); scanf("%d", &n); for (int i = 0; i < n; i++) { scanf("%lf %lf", &p.x, &p.y); ans = project(s, p); printf("%.10lf %.10lf\n", ans.x, ans.y); }
CGL_1_B:Reflection
求点在这条直线的对称点
Segment s; Point p, ans; int n; scanf("%lf %lf %lf %lf", &s.p1.x, &s.p1.y, &s.p2.x, &s.p2.y); scanf("%d", &n); for (int i = 0; i < n; i++) { scanf("%lf %lf", &p.x, &p.y); ans = reflect(s, p); printf("%.10lf %.10lf\n", ans.x, ans.y); }
CGL_2_D:Distance
求线段s1和s2之间的距离
Segment s1, s2; int n; scanf("%d", &n); while (n--) { scanf("%lf %lf %lf %lf %lf %lf %lf %lf", &s1.p1.x, &s1.p1.y, &s1.p2.x, &s1.p2.y, &s2.p1.x, &s2.p1.y, &s2.p2.x, &s2.p2.y); printf("%.10lf\n", getDistance(s1, s2)); }
CGL_1_C:Counter-Clockwise
求三个点的逆时针方向
Point p1, p2; Point p, ans; int n; scanf("%lf %lf %lf %lf", &p1.x, &p1.y, &p2.x, &p2.y); scanf("%d", &n); for (int i = 0; i < n; i++) { scanf("%lf %lf", &p.x, &p.y); int ans = ccw(p1, p2, p); if (ans == 1) printf("COUNTER_CLOCKWISE\n"); else if (ans == -1) printf("CLOCKWISE\n"); else if (ans == 2) printf("ONLINE_BACK\n"); else if (ans == -2) printf("ONLINE_FRONT\n"); else printf("ON_SEGMENT\n"); }
CGL_2_B:Intersection
判断两个线段是否相交
Segment s1, s2; int n; scanf("%d", &n); while (n--) { scanf("%lf %lf %lf %lf %lf %lf %lf %lf", &s1.p1.x, &s1.p1.y, &s1.p2.x, &s1.p2.y, &s2.p1.x, &s2.p1.y, &s2.p2.x, &s2.p2.y); printf("%d\n", intersect(s1, s2) ? 1 : 0); }
CGL_2_C:Cross Point
求线段s1,s2的交点
Segment s1, s2; int n; scanf("%d", &n); while (n--) { scanf("%lf %lf %lf %lf %lf %lf %lf %lf", &s1.p1.x, &s1.p1.y, &s1.p2.x, &s1.p2.y, &s2.p1.x, &s2.p1.y, &s2.p2.x, &s2.p2.y); Point ans = getCrossPoint(s1, s2); printf("%.10lf %.10lf\n", ans.x, ans.y); }
CGL_7_D:Cross Points of a Circle and a Line
求圆和直线的交点,题目限制圆与直线存在交点。实际上,只要检查圆心到直线的距离是否大于r就知道圆与直线是否存在交点。
Circle c; Line l; int n; scanf("%lf %lf %lf", &c.c.x, &c.c.y, &c.r); scanf("%d", &n); while (n--) { scanf("%lf %lf %lf %lf", &l.p1.x, &l.p1.y, &l.p2.x, &l.p2.y); pair<Point, Point> ans = getCrossPoints(c, l); if(ans.first < ans.second) printf("%.10lf %.10lf %.10lf %.10lf\n", ans.first.x, ans.first.y, ans.second.x, ans.second.y); else printf("%.10lf %.10lf %.10lf %.10lf\n", ans.second.x, ans.second.y, ans.first.x, ans.first.y); }
CGL_7_E:Cross Points of Circles
求两个圆的交点,题目限制两个圆存在交点。实际上,只要检查两圆心的距离是否大于r1 + r2就知道两个圆是否存在交点。
Circle c1, c2; scanf("%lf %lf %lf", &c1.c.x, &c1.c.y, &c1.r); scanf("%lf %lf %lf", &c2.c.x, &c2.c.y, &c2.r); pair<Point, Point> ans = getCrossPoints(c1, c2); if (ans.first < ans.second) printf("%.10lf %.10lf %.10lf %.10lf\n", ans.first.x, ans.first.y, ans.second.x, ans.second.y); else printf("%.10lf %.10lf %.10lf %.10lf\n", ans.second.x, ans.second.y, ans.first.x, ans.first.y);
CGL_3_C:Polygon-Point Containment
求点在多边形的位置,若在里面则输出2,若在边上则输出1,在外面则输出0
Polygon g; Point p ,t; int n, q; scanf("%d", &n); for (int i = 0; i < n; i++) { scanf("%lf %lf", &t.x, &t.y); g.push_back(t); } scanf("%d", &q); for (int i = 0; i < q; i++) { scanf("%lf %lf", &p.x, &p.y); printf("%d\n", contains(g, p)); }
CGL_4_A:Convex Hull
求点集合P的凸包,需要按照从最左侧最下端开始输出。
Polygon g, ans ,temp; Point t; int n, len; scanf("%d", &n); for (int i = 0; i < n; i++) { scanf("%lf %lf", &t.x, &t.y); g.push_back(t); } ans = andrewScan(g); temp = ans; // 选出最左侧最下端的点开始输出 sort(temp.begin(), temp.end(),cmp); int index; for (int i = 0; i < ans.size(); i++) if (ans[i] == temp[0]) index = i; printf("%d\n", ans.size()); for (int i = 0; i < ans.size(); i++) printf("%d %d\n", int(ans[(i + index) % ans.size()].x), int(ans[(i + index) % ans.size()].y));
相关文章推荐
- 计算几何模版
- 计算几何 常用算法模版
- 【模版】计算几何
- 计算几何模版
- 计算几何模版(点,线)
- 计算几何模版
- 计算几何模版
- HDU 3007 Buried memory(计算几何の最小圆覆盖,模版题)
- 计算几何的一些模版
- 平面计算几何模版集合
- 九野的计算几何模版
- 九野的计算几何模版
- HDU 4643 GSM (2013多校5 1001题 计算几何)
- (2017多校6)1002/hdu-6097 Mindis(计算几何)
- 平行x 轴的线段 是否 遮掩 计算几何的扩大数据运算的典型应用,扩大根号2倍之后就避免了小数。 poj 3347 Kadj Squares
- 函数模版之几何面积
- TOYS POJ - 2318 计算几何
- 计算几何常用总结
- 计算几何
- 计算几何入门题推荐、计算几何题目合集