参考文章 https://blog.csdn.net/clover_hxy/article/details/53966405
预备知识
先来个小数读入优化
double read() { double x = 0, f = 1, y = 0.1; char ch = getchar(); for (; !isdigit(ch)&&ch!='.'; ch=getchar()) if (ch=='-') f = -1; for (; isdigit(ch); ch=getchar()) x = x * 10 + ch - '0'; if (ch == '.') ch = getchar(); for (; isdigit(ch); ch=getchar()) x += (ch - '0') * y, y *= 0.1; return x * f; }
常用模板
const double eps = 1e-8; const double Pi = acos(-1.0); struct Vector{ double x,y; Vector() {} Vector(double a,double b) { x = a, y = b; } }; typedef Vector Point; Vector operator + (Vector a,Vector b) { return Vector(a.x+b.x, a.y+b.y); } Vector operator - (Vector a,Vector 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); } bool operator == (Point a,Point b) { return (a.x == b.x) && (a.y == b.y); }
精度控制
int dcmp(double x) { if (fabs(x) <= eps) return 0; return x > 0 ? x : -x; }
向量
向量模长
double len(Vector a) { return sqrt(a.x * a.x + a.y * a.y); }
点积
double dot(Vector a, Vector b) { return a.x * b.x + a.y * b.y; }
叉积
叉积判断两向量的位置,将两向量共起点,设一号向量为A,另一个为B,若B可以由A逆时针旋转某个度数(大于等于0,小于等于180),那么Cross(A,B) > 0,否则小于0
double cross(Vector a, Vector b) { return a.x * b.y - a.y * b.x; }
向量之间的夹角
double Angle(Vector a, Vector b) { return acos(dot(a,b)/len(a)/len(b)); }
旋转,p是旋转角度(逆时针),弧度制。
Vector rotate(Vector a,double p) { return Vector(a.x * cos(p) - a.y * sin(p), a.x * sin(p) + a.y * cos(p)); }
法向量
Vector normal(Vector a) { double L = len(a); return Vector(-a.y/L, a.x/L); }
点与直线
点到直线的距离
double distl(Point p,Point a,Point b) { Vector v = p - a, u = b - a; return fabs(cross(v,u)) / len(u); }
点到线段的距离
double dists(Point p,Point a,Point b) { if (a==b) return len(p-a); Vector v1 = p - a, v2 = p - b, v3 = b - a; if (dcmp(dot(v1,v3)) < 0) return len(v1); else if (dcmp(dot(v2,a-b)) < 0) return len(v2); return fabs(cross(v2,v3))/len(v3); }
判断直线是否相交
bool xiangjiao(Point a,Point b,Point c,Point d) { double u1 = cross(b-a,c-a), u2 = cross(b-a,d-a); double v1 = cross(d-c,a-c), v2 = cross(d-c,b-c); return dcmp(u1 * u2) < 0 && dcmp(v1 * v2) < 0; }
求两直线的交点
Point jiaodian(Line a, Line b) { Point A = a.s, B = a.t, C = b.s, D = b.t; double t1 = cross(D - A, B - A), t2 = cross(B - A, C - A); double t = t1 / (t1 + t2); return C * t + D * (1 - t); }
多边形
判断点是否在多边形内
int pointin(Point p,Point* a,int n) { int flag = 0; for (int i=1; i<=n; ++i) { Point s = a[i], t = a[i % n + 1]; if (p == s || p == t) return -1; // 在点上 if ((s.y < p.y && t.y >= p.y) || (s.y >= p.y && t.y < p.y)) { int x = s.x + (p.y - s.y) * (t.x - s.x) / (t.y - s.y); // 射线与线段的交点的横坐标 if (x == p.x) return -1; // 在边上 if (x > p.x) flag ++; // 过这条边,且在p的右边 } } return flag & 1; }
求多边形的面积
double Area(Point *a,int n) { double ans = 0; for (int i=2; i<n; ++i) ans += cross(a[i]-a[1],a[i+1]-a[1]); return ans / 2.0; }