转自:http://bbs.byr.cn/#!article/ACM_ICPC/63442
/* Project: AkemiHomura's Standard Code Library [AHSCL] Author: [BUPT]AkemiHomura@PuellaMagi Category: Geometry Title: Geometry Base Header Version: 0.103 Date: 2011-5-3 Remark: Structure definations and base functions Tested Problems: N/A Tag: Geometry Special Thanks: Amber, eucho@PuellaMagi, mabodx@PuellaMagi */ #ifndef GEOMETRY_BASE_H #define GEOMETRY_BASE_H #include <cstdio> #include <cmath> #include <algorithm> using namespace std; /***<常量表****/ const int MAXN = 1000; const double INF = 1e9; const double EPS = 1e-8; const double PI = acos(-1.0); /****常量表>***/ /***<浮点函数****/ inline int sgn(double d) { if (fabs(d) < EPS) return 0; return d>0 ? 1: -1; } inline double min(double a, double b) {return a<b ? a : b;} inline double max(double a, double b) {return a>b ? a : b;} /****浮点函数>***/ /*******<平面几何********/ /***<点/向量定义与运算****/ struct sp { double x, y; double d, a; int id; sp() {} sp(double xx, double yy): x(xx), y(yy) {} bool read() {return scanf("%lf%lf", &x, &y)==2;} void write() {printf("%f %f\n", x, y);} }; inline sp operator- (const sp &u, const sp &v) {return sp(u.x-v.x, u.y-v.y);} inline sp operator+ (const sp &u, const sp &v) {return sp(u.x+v.x, u.y+v.y);} inline sp operator* (double d, const sp &v) {return sp(v.x*d, v.y*d);} inline bool operator== (const sp &u, const sp &v) {return sgn(u.x-v.x)==0 && sgn(u.y-v.y)==0;} inline bool operator!= (const sp &u, const sp &v) {return !(u == v);} const sp ORIGIN = sp(0, 0); /****点/向量定义与运算>***/ /***<线段/直线定义****/ struct ss { sp a, b; ss() {} ss(sp u, sp v): a(u), b(v) {} }; /****线段/直线定义>***/ /***<点与线基本函数****/ //向量范数平方 double nrmsqr(const sp &v) {return v.x*v.x + v.y*v.y;} //点积 double dot(const sp &u, const sp &v) {return u.x*v.x + u.y*v.y;} //叉积 double det(const sp &u, const sp &v) {return u.x*v.y - v.x*u.y;} //(u-p)x(v-p) //等于0表示3点共线 //大于0表示pv在pu的逆时针,小于0表示pv在pu的顺时针 double dir(const sp &p, const sp &u, const sp &v) {return det(u-p, v-p);} //两点距离 double dis(const sp &u, const sp &v) { double dx = u.x-v.x; double dy = u.y-v.y; return sqrt(dx*dx+dy*dy); } //两点距离平方,针对精度问题 double dissqr(const sp &u, const sp &v) {return nrmsqr(v-u);} //点到直线距离 double disptoline(const sp &p, const ss &s) {return fabs(det(p-s.a, s.b-s.a))/dis(s.b, s.a);} //点到线段最近点 sp ptoseg(const sp &p, const ss &s) { sp v = s.b-s.a, res; double t = (dot(p, v)-dot(s.a, v))/dot(v, v); if (sgn(t)>=0 && sgn(t-1)<=0) res = s.a+(t*v); else res = dis(p, s.a)<dis(p, s.b) ? s.a : s.b; return res; } //点到线段距离 double disptoseg(const sp &p, const ss &s) {return dis(p, ptoseg(p, s));} //p相对p0极角 double pa(const sp &p, const sp &p0 = ORIGIN) {return atan2(p.y-p0.y, p.x-p0.x);} //将点p绕点p0旋转a弧度 sp rotate(const sp &p, double a, const sp &p0 = ORIGIN) { sp res = p0, v = p-p0; double c = cos(a), s = sin(a); res.x += v.x*c-v.y*s; res.y += v.x*s+v.y*c; return res; } //判三点共线 bool coline(const sp &p0, const sp &p1, const sp &p2) {return sgn(dir(p0, p1, p2))==0;} //点p是否在直线s上 bool online(const sp &p, const ss &s) {return coline(p, s.a, s.b);} //点p是否在线段s上 bool onseg(const sp &p, const ss &s) {return online(p, s) && (s.a.x-p.x)*(s.b.x-p.x)<EPS && (s.a.y-p.y)*(s.b.y-p.y)<EPS;} //判两点在线段同侧,点在线段上返回0 bool sameside(const sp &u, const sp &v, const ss &s) {return dir(s.b, s.a, u)*dir(s.b, s.a, v)>EPS;} //判两点在线段异侧,点在线段上返回0 bool oppositeside(const sp &u, const sp &v, const ss &s) {return dir(s.b, s.a, u)*dir(s.b, s.a, v)<-EPS;} //直线u和v是否相交 bool lineint(const ss &u, const ss &v) {return sgn(det(u.b-u.a, v.b-v.a))!=0;} //线段u和v是否相交(包括端点) bool segint(const ss &u, const ss &v) { if (!coline(u.a, u.b, v.a) || !coline(u.a, u.b, v.b)) return !sameside(u.a, u.b, v) && !sameside(v.a, v.b, u); else return onseg(u.a, v) || onseg(u.b, v) || onseg(v.a, u) || onseg(v.b, u); } //计算两直线交点,结果赋予p //返回值: 0 共线, 1 平行, 2 相交 char lineintp(const ss &u, const ss &v, sp &p) { double a1, b1, c1, a2, b2, c2; a1 = u.b.y - u.a.y; b1 = u.a.x - u.b.x; c1 = det(u.b, u.a); a2 = v.b.y - v.a.y; b2 = v.a.x - v.b.x; c2 = det(v.b, v.a); //判断是否共线或平行,确定相交时可以去掉 if (sgn(a1*b2-b1*a2)==0) //There may be some mistakes if (sgn(det(u.a-v.a, u.a-v.b))==0) return 0; else return 1; else { double t = a2*b1-a1*b2; p.x = (b2*c1-b1*c2)/t; p.y = (a1*c2-a2*c1)/t; return 2; } } /****点与线基本函数>***/ /***<面积****/ //三角形三个点有向面积 double area(const sp &a, const sp &b, const sp &c) {return dir(a, b, c)/2;} //三角形三条边面积 double area(double p, double q, double r) { double s = (p+q+r)/2; return sqrt(s*(s-p)*(s-q)*(s-r)); } //多边形面积 double area(int N, sp poly[]) { double res = 0; if (N < 3) return 0; for (int i = 0; i < N; ++i) res += det(poly[i], poly[(i+1)%N]); return res/2; } /****面积>***/ /***<圆****/ //判直线和圆相交(包括相切) bool linecirint(const sp &c, double r, const ss &s) {return sgn(disptoline(c, s)-r)<=0;} //求点到圆的切点 //求出后可直接求切线 //点在圆内返回0,圆上返回1与点本身,否则返回2与两个切点 char tgp(const sp &c, double r, const sp &p, sp &u, sp &v) { char cv = sgn(dis(p, c)-r); if (cv < 0) return 0; if (cv == 0) {u = p; return 1;} double a = pa(p, c); double da = acos(r/dis(p, c)); u.x = c.x+r*cos(a+da); u.y = c.y+r*sin(a+da); v.x = c.x+r*cos(a-da); v.y = c.y+r*sin(a-da); return 2; } //两圆外公切线 //输入两圆心和半径 //返回两直线s和t //s和t的a对应u上切点,b对应v上切点 void cotgl(const sp &u, double ru, const sp &v, double rv, ss &s, ss &t) { double dr = ru-rv; double d = dis(u, v); double a = acos(dr/d); sp dv = v-u; s.a = u+ru/d*rotate(dv, a); s.b = v+rv/d*rotate(dv, a); t.a = u+ru/d*rotate(dv, -a); t.b = v+rv/d*rotate(dv, -a); } //两圆内公切线 //输入两圆心和半径 //返回两直线s和t //s和t的a对应u上切点,b对应v上切点 void citgl(const sp &u, double ru, const sp &v, double rv, ss &s, ss &t) { double dr = ru+rv; double d = dis(u, v); double a = acos(dr/d); sp dv = v-u; s.a = u+ru/d*rotate(dv, a); s.b = v+rv/d*rotate(dv, a-PI); t.a = u+ru/d*rotate(dv, -a); t.b = v+rv/d*rotate(dv, PI-a); } //求三点共圆 //共圆返回true,并返回圆心,半径,否则返回false bool concylic(const sp &p1, const sp &p2, const sp &p3, sp &c, double r) { if (sgn(dir(p1, p2, p3))==0) return 0; double t1 = nrmsqr(p1)-nrmsqr(p2); double t2 = nrmsqr(p1)-nrmsqr(p3); double t3 = 2*(p1.x-p2.x)*(p1.y-p3.y)-2*(p1.x-p3.x)*(p1.y-p2.y); c.x = ((p1.y-p3.y)*t1-(p1.y-p2.y)*t2)/t3; c.y = -((p1.x-p3.x)*t1-(p1.x-p2.x)*t2)/t3; r = dis(c, p1); return 1; } /****圆>***/ /***<多边形****/ //多边形p是否以逆时针顺序给出 bool ccw(int N, sp p[]) { double cnt = 0; for (int i = 0; i < N; ++i) cnt += dir(p[i], p[(i+1)%N], ORIGIN); return sgn(cnt) > 0; } //点p是否在凸多边形c内 //输入:N为凸多边形点数,c为凸多边形,p为点。c中的点必须按逆时针序给出。 //输出:返回1表示(严格)在内部,0表示不在内部。 bool inside(int N, sp c[], sp p) { int l=1, r=N-1, m; while (l < r) { m = l+r>>1; if (sgn(dir(c[0], c[m], p)) <= 0) r = m; else l = m+1; } if (r==1 || sgn(dir(c[0], c[N-1], p))>=0 || sgn(dir(c[r], c[r-1], p))>=0) return 0; return 1; } //多边形切割 //将N个点的多边形p(逆时针输入)按直线s切割,留下side方向的部分 //剩下的部分返回在q(逆时针),返回q的点数 //可用于半平面交和多边形交 int polycut(int N, sp p[], const ss &s, const sp &side, sp q[]) { sp pp[111]; int M = 0, res = 0, i; for (i = 0; i < N; ++i) { if (sameside(p[i], side, s)) pp[M++] = p[i]; if (!sameside(p[i], p[(i+1)%N], s) && !(sgn(dir(s.b, p[i], s.a))==0 && sgn(dir(s.b, p[(i+1)%N], s.a))==0)) lineintp(ss(p[i], p[(i+1)%N]), s, pp[M++]); } for (res = i = 0; i < M; ++i) { if (!i || sgn(pp[i].x-pp[i-1].x)!=0 || sgn(pp[i].y-pp[i-1].y)!=0) q[res++] = pp[i]; } if (sgn(q[res-1].x-q[0].x)==0 && sgn(q[res-1].y-q[0].y)==0) res--; if (res < 3) res = 0; return res; } /****多边形>***/ //两圆交点 //返回两圆是否相交(相切不算) //交点返回在a和b中 bool cirint(const sp &u, double ru, const sp &v, double rv, sp &a, sp &b) { double d = dis(u, v); if (sgn(d-(ru+rv))>=0 || sgn(d-fabs(ru-rv))<=0) return 0; sp c = u-v; double ca, sa, cb, sb, csum, ssum; ca = c.x/d, sa = c.y/d; cb = (rv*rv+d*d-ru*ru)/2/rv/d, sb = sqrt(1-cb*cb); csum = ca*cb-sa*sb; ssum = sa*cb+sb*ca; a = sp(rv*csum, rv*ssum); a = a+v; sb = -sb; csum = ca*cb-sa*sb; ssum = sa*cb+sb*ca; b = sp(rv*csum, rv*ssum); b = b+v; return 1; } //Scan Line //Ring Scan Line //return how many points in the half plane left to the line determined by P[Origin](origin) and P[j] //NOT include points on the radial (P[Origin], P[st]), //BUT may include points on the reverse radial (st from P[Origin], and the reverse direction), it depends //ptmp is a copy of point set P inline bool cmp(const sp &u, const sp &v) {return u.a < v.a;} void ringscan(int N, sp p[], int origin, int cnt[]) { sp ptmp[MAXN]; for (int i = 0; i < N; ++i) { ptmp[i] = p[i]; ptmp[i].id = i; } swap(ptmp[origin], ptmp[N-1]); for (int i = 0; i < N-1; ++i) ptmp[i].a = atan2(ptmp[i].y-ptmp[N-1].y, ptmp[i].x-ptmp[N-1].x); sort(ptmp, ptmp+N-1, cmp); //NOT include points in the reverse radial for (int st = 0, ed = 0; st < N-1; ++st) { if (ed == st) ed++; while ((ed<st+N-1) && (sgn(dir(ptmp[N-1], ptmp[st], ptmp[ed%(N-1)]))>0)) ed++; cnt[st] = ed-1-st; } //include points in the reverse radial /* for (int st = 0, ed = 0; st < N-1; ++st) { while ((ed<st+N-1) && (sgn(dir(ptmp[N-1], ptmp[st], ptmp[ed%(N-1)]))>=0)) ed++; cnt[st] = ed-1-st; } */ } #endif
/* Project: Biribiri Standard Code Library [BSCL] Author: [BUPT]AkemiHomura Category: Geometry Title: Graham Scan Version: 0.314 Date: 2011-1-31 Remark: Find the the convex hull of point set P Tested Problems: POJ1113 Tag: geometry, convex hull, Graham Scan Special Thanks: Amber */ /* Input: A set of points p[] Output: The convex hull ch[], and the number of the points in it */ #include <cmath> #include <algorithm> using namespace std; const double INF = 1e9; const double EPS = 1e-8; const double PI = acos(-1.0); inline int sgn(double d) { if (fabs(d) < EPS) return 0; return d>0 ? 1 : -1; } struct sp { double x, y; sp () {} sp (double xx, double yy): x(xx), y(yy) {} }; inline sp operator- (const sp &u, const sp &v) {return sp(u.x-v.x, u.y-v.y);} double det(const sp &u, const sp &v) {return u.x*v.y - v.x*u.y;} double dir(const sp &p, const sp &u, const sp &v) {return det(u-p, v-p);} bool cmp(const sp &u, const sp &v) { if (sgn(u.y-v.y)==0) return u.x>v.x; return u.y>v.y; } //输入点数N,点集p,bool变量in表示是否包括三点共线中间点,默认为false,为true可能会退化 //返回凸包点数,凸包集ch int graham(int N, sp p[], sp ch[], bool in = 0) { const double e = in ? EPS : -EPS; int i, j, k; if (N < 3) { for (i = 0; i < N; ++i) ch[i] = p[i]; return N; } sort(p, p+N, cmp); ch[0] = p[0]; ch[1] = p[1]; for (i = j = 2; i < N; ch[j++]=p[i++]) while (j>1 && dir(ch[j-1], ch[j-2], p[i])>e) --j; ch[k=j++] = p[N-2]; for (i = N-3; i > 0; ch[j++]=p[i--]) while (j>k && dir(ch[j-1], ch[j-2], p[i])>e) --j; while (j>k && dir(ch[j-1], ch[j-2], ch[0])>e) --j; return j; }圆交/并
#include <cmath> #include <algorithm> using namespace std; const double PI = acos(-1.0); const double EPS = 1e-8; int sgn(double d) { if (fabs(d)<EPS) return 0; return d>0?1:-1; } struct sp { double x, y; double pa; int cnt; sp() {} sp(double a, double b): x(a), y(b) {} sp(double a, double b, double c, int d): x(a), y(b), pa(c), cnt(d) {} bool operator<(const sp &rhs) const { return pa<rhs.pa; } void read() {scanf("%lf%lf", &x, &y);} void write() {printf("%lf %lf\n", x, y);} }; sp operator+(const sp &u, const sp &v) { return sp(u.x+v.x, u.y+v.y); } sp operator-(const sp &u, const sp &v) { return sp(u.x-v.x, u.y-v.y); } double det(const sp &u, const sp &v) { return u.x*v.y-v.x*u.y; } double dir(const sp &p, const sp &u, const sp &v) { return det(u-p, v-p); } double dis(const sp &u, const sp &v) { double dx = u.x-v.x; double dy = u.y-v.y; return sqrt(dx*dx+dy*dy); } //计算两圆交点 //输入圆心坐标和半径 //返回两圆是否相交(相切不算) //如果相交,交点返回在a和b(从a到b为u的交弧) bool cirint(const sp &u, double ru, const sp &v, double rv, sp &a, sp &b) { double d = dis(u, v); if (sgn(d-(ru+rv))>=0 || sgn(d-fabs(ru-rv))<=0) return 0; sp c = u-v; double ca, sa, cb, sb, csum, ssum; ca = c.x/d, sa = c.y/d; cb = (rv*rv+d*d-ru*ru)/2/rv/d, sb = sqrt(1-cb*cb); csum = ca*cb-sa*sb; ssum = sa*cb+sb*ca; a = sp(rv*csum, rv*ssum); a = a+v; sb = -sb; csum = ca*cb-sa*sb; ssum = sa*cb+sb*ca; b = sp(rv*csum, rv*ssum); b = b+v; return 1; } sp e[222]; int cover[111]; //求圆并 //输入点数N,圆心数组p,半径数组r,答案数组s //s[i]表示被至少i个圆覆盖的面积(最普通的圆并就是s[1]) void circle_union(int N, int p[], double r[], double s[]) { int i, j, k; for (i = 0; i < N; ++i) for (j = 0; j < N; ++j) { double rd = r[i]-r[j]; if (i!=j && sgn(rd)>0 && sgn(dis(p[i], p[j])-rd)<=0) cover[j]++; } for (i = 0; i < N; ++i) { int ecnt = 0; e[ecnt++] = sp(p[i].x-r[i], p[i].y, -PI, 1); e[ecnt++] = sp(p[i].x-r[i], p[i].y, PI, -1); for (j = 0; j < N; ++j) { if (j==i) continue; if (cirint(p[i], r[i], p[j], r[j], a, b)) { e[ecnt++] = sp(a.x, a.y, atan2(a.y-p[i].y, a.x-p[i].x), 1); e[ecnt++] = sp(b.x, b.y, atan2(b.y-p[i].y, b.x-p[i].x), -1); if (sgn(e[ecnt-2].pa-e[ecnt-1].pa)>0) { e[0].cnt++; e[1].cnt--; } } } sort(e, e+ecnt); int cnt = e[0].cnt; for (j = 1; j < ecnt; ++j) { double pad = e[j].pa-e[j-1].pa; s[cover[i]+cnt] += (det(e[j-1], e[j])+r[i]*r[i]*(pad-sin(pad)))/2; cnt += e[j].cnt; } } }
#include <cmath> #include <algorithm> using namespace std; const double EPS = 1e-8; struct sp { double x, y; sp () {} sp (double xx, double yy): x(xx), y(yy) {} }; inline sp operator- (const sp &u, const sp &v) {return sp(u.x-v.x, u.y-v.y);} double nrmsqr(const sp &v) {return v.x*v.x + v.y*v.y;} double dis(const sp &u, const sp &v) { double dx = u.x-v.x; double dy = u.y-v.y; return sqrt(dx*dx+dy*dy); } double fermatpoint(int N, sp p[]) { sp u, v; double step = 0; u.x = u.y = 0; for (int i = 0; i < N; ++i) { u.x += p[i].x; u.y += p[i].y; } step = u.x+u.y; u.x /= N; u.y /= N; double now, best = 0; for (int i = 0; i < N; ++i) best += dis(u, p[i]); while (step > EPS) { for (int i = -2; i <= 2; ++i) for (int j = -2; j <= 2; ++j) { v.x = u.x+step*i; v.y = u.y+step*j; now = 0; for (int k = 0; k < N; ++k) now += dis(v, p[i]); if (now < best) { best = now; u = v; } } //影响ac,wa,tle... step /= 1.1; } return best; }
#include <cmath> #include <algorithm> using namespace std; const double EPS = 1e-8; inline int sgn(double d) { if (fabs(d) < EPS) return 0; return d>0 ? 1: -1; } struct sp { double x, y; sp() {} sp(double xx, double yy): x(xx), y(yy) {} }; inline sp operator- (const sp &u, const sp &v) {return sp(u.x-v.x, u.y-v.y);} inline bool operator== (const sp &u, const sp &v) {return sgn(u.x-v.x)==0 && sgn(u.y-v.y)==0;} struct ss { sp a, b; ss() {} ss(sp u, sp v): a(u), b(v) {} }; double det(const sp &u, const sp &v) {return u.x*v.y - v.x*u.y;} double dir(const sp &p, const sp &u, const sp &v) {return det(u-p, v-p);} bool coline(const sp &p0, const sp &p1, const sp &p2) {return sgn(dir(p0, p1, p2))==0;} bool online(const sp &p, const ss &s) {return coline(p, s.a, s.b);} bool onseg(const sp &p, const ss &s) {return online(p, s) && (s.a.x-p.x)*(s.b.x-p.x)<EPS && (s.a.y-p.y)*(s.b.y-p.y)<EPS;} bool sameside(const sp &u, const sp &v, const ss &s) {return dir(s.b, s.a, u)*dir(s.b, s.a, v)>EPS;} bool segint(const ss &u, const ss &v) { if (!coline(u.a, u.b, v.a) || !coline(u.a, u.b, v.b)) return !sameside(u.a, u.b, v) && !sameside(v.a, v.b, u); else return onseg(u.a, v) || onseg(u.b, v) || onseg(v.a, u) || onseg(v.b, u); } char lineintp(const ss &u, const ss &v, sp &p) { double a1, b1, c1, a2, b2, c2; a1 = u.b.y - u.a.y; b1 = u.a.x - u.b.x; c1 = det(u.b, u.a); a2 = v.b.y - v.a.y; b2 = v.a.x - v.b.x; c2 = det(v.b, v.a); if (sgn(a1*b2-b1*a2)==0) if (sgn(det(u.a-v.a, u.a-v.b))==0) return 0; else return 1; else { double t = a2*b1-a1*b2; p.x = (b2*c1-b1*c2)/t; p.y = (a1*c2-a2*c1)/t; return 2; } } int polycut(int N, sp p[], const ss &s, const sp &side, sp q[]) { sp pp[111]; int M = 0, res = 0, i; for (i = 0; i < N; ++i) { if (sameside(p[i], side, s)) pp[M++] = p[i]; if (!sameside(p[i], p[(i+1)%N], s) && !(sgn(dir(s.b, p[i], s.a))==0 && sgn(dir(s.b, p[(i+1)%N], s.a))==0)) lineintp(ss(p[i], p[(i+1)%N]), s, pp[M++]); } for (res = i = 0; i < M; ++i) { if (!i || sgn(pp[i].x-pp[i-1].x)!=0 || sgn(pp[i].y-pp[i-1].y)!=0) q[res++] = pp[i]; } if (sgn(q[res-1].x-q[0].x)==0 && sgn(q[res-1].y-q[0].y)==0) res--; if (res < 3) res = 0; return res; } bool cmp(const sp &u, const sp &v) { if (sgn(u.y-v.y)==0) return u.x>v.x; return u.y>v.y; } int graham(int N, sp p[], sp ch[], bool in = 0) { const double e = in ? EPS : -EPS; int i, j, k; if (N < 3) { for (i = 0; i < N; ++i) ch[i] = p[i]; return N; } sort(p, p+N, cmp); ch[0] = p[0]; ch[1] = p[1]; for (i = j = 2; i < N; ch[j++]=p[i++]) while (j>1 && dir(ch[j-1], ch[j-2], p[i])>e) --j; ch[k=j++] = p[N-2]; for (i = N-3; i > 0; ch[j++]=p[i--]) while (j>k && dir(ch[j-1], ch[j-2], p[i])>e) --j; while (j>k && dir(ch[j-1], ch[j-2], ch[0])>e) --j; return j; } //凸多边形交 //输入两个多边形p和q(逆时针)及相应点数N和M //返回两个多边形的交于r,返回点数 //graham为可选步骤,最好做一下保证正确性 int polyint(int N, sp p[], int M, sp q[], sp r[]) { int i, j, k; sp t[111]; for (i = 0; i < N; ++i) t[i] = p[i]; int res = N; for (i = 0; i < M; ++i) { res = polycut(res, t, ss(q[i], q[(i+1)%M]), q[(i+2)%M], t); if (res==0) return 0; } res = graham(res, t, r); return res; }
/* Project: AkemiHomura's Standard Code Library [AHSCL] Author: [BUPT]AkemiHomura@PuellaMagi Category: Geometry Title: Radius Circle Cover Version: 0.103 Date: 2011-8-17 Remark: Given a point set P, find a circle with a given radius R that covers the most points in P Tested Problems: Ural1332 Tag: Geometry Special Thanks: Amber, eucho@PuellaMagi, mabodx@PuellaMagi */ #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> using namespace std; const double EPS = 1e-8; const double PI = acos(-1.0); inline int sgn(double d) { if (fabs(d)<EPS) return 0; return d>0?1:-1; } struct sp { double x, y; sp() {} sp(double xx, double yy): x(xx), y(yy) {} void read() {scanf("%lf%lf", &x, &y);} }; inline sp operator- (const sp &u, const sp &v) {return sp(u.x-v.x, u.y-v.y);} double dis(const sp &u, const sp &v) { double dx = u.x-v.x; double dy = u.y-v.y; return sqrt(dx*dx+dy*dy); } double pa(const sp &p, const sp &p0) {return atan2(p.y-p0.y, p.x-p0.x);} struct sarc { double a; char cnt; sarc() {} sarc(double aa, int cc): a(aa), cnt(cc) {} }; bool operator< (const sarc &a1, const sarc &a2) { //if (sgn(a1.a-a2.a)==0) return a1.cnt>a2.cnt; return a1.a<a2.a; } //给定半径圆覆盖 //输入点集大小N,点集p,给定半径r //返回能覆盖最多点的点数及圆心c int rcc(int N, sp p[], double r, sp &c) { if (sgn(r)<0) return 0; c = p[0]; if (sgn(r)==0) return 1; sarc arc[1000]; int arccnt, swpcnt, res = 1; double d, a, da, as, ae; for (int i = 0; i < N; ++i) { swpcnt = arccnt = 0; for (int j = 0; j < N; ++j) { if (i==j) continue; d = dis(p[i], p[j]); if (sgn(d-r-r)>0) continue; a = pa(p[j], p[i]); da = acos(d/(2*r)); if (sgn(da)==0) { arc[arccnt++] = sarc(a, 1); arc[arccnt++] = sarc(a, -1); continue; } as = a-da; ae = a+da; if (sgn(as+PI)<0) as += 2*PI; if (sgn(ae-PI)>0) ae += 2*PI; if (sgn(as-ae)>0) { arc[arccnt++] = sarc(as, 1); arc[arccnt++] = sarc(PI, -1); arc[arccnt++] = sarc(-PI, 1); arc[arccnt++] = sarc(ae, -1); } else { arc[arccnt++] = sarc(as, 1); arc[arccnt++] = sarc(ae, -1); } } sort(arc, arc+arccnt); for (int j = 0; j < arccnt; ++j) { swpcnt += arc[j].cnt; if (swpcnt+1 > res) { res = swpcnt+1; c.x = p[i].x+r*cos(arc[j].a); c.y = p[i].y+r*sin(arc[j].a); } } } return res; }
/* Project: AkemiHomura's Standard Code Library [AHSCL] Author: [BUPT]AkemiHomura@PuellaMagi Category: Geometry Title: Minimum Circle Cover Version: 0.103 Date: 2011-5-3 Remark: Given a point set P, find the circle with minimum radius that covers all the points in P Tested Problems: N/A Tag: Geometry Special Thanks: Amber, eucho@PuellaMagi, mabodx@PuellaMagi */ #include <cmath> #include <algorithm> using namespace std; const double EPS = 1e-9; inline int sgn(double d) { if (fabs(d) < EPS) return 0; return d>0?1:-1; } struct sp { double x, y; sp() {} sp(double xx, double yy): x(xx), y(yy) {} }; inline sp operator- (const sp &u, const sp &v) {return sp(u.x-v.x, u.y-v.y);} double nrmsqr(const sp &v) {return v.x*v.x+v.y*v.y;} double dis(const sp &u, const sp &v) { double dx = u.x-v.x; double dy = u.y-v.y; return sqrt(dx*dx+dy*dy); } double det(const sp &u, const sp &v) {return u.x*v.y - v.x*u.y;} double dir(const sp &p, const sp &u, const sp &v) {return det(u-p, v-p);} bool concylic(const sp &p1, const sp &p2, const sp &p3, sp &c, double r) { if (sgn(dir(p1, p2, p3))==0) return 0; double t1 = nrmsqr(p1)-nrmsqr(p2); double t2 = nrmsqr(p1)-nrmsqr(p3); double t3 = 2*(p1.x-p2.x)*(p1.y-p3.y)-2*(p1.x-p3.x)*(p1.y-p2.y); c.x = ((p1.y-p3.y)*t1-(p1.y-p2.y)*t2)/t3; c.y = -((p1.x-p3.x)*t1-(p1.x-p2.x)*t2)/t3; r = dis(c, p1); return 1; } //mcc:minimum circle cover //最小圆覆盖 //输入点集大小N,点集p //返回覆盖所有点的最小圆的圆心c,半径r void mcc(int N, sp p[], sp &c, double &r) { random_shuffle(p, p+N); c = p[0]; r = 0; for (int i = 1; i < N; ++i) if (sgn(dis(p[i],c)-r)>0) { c = p[i]; r = 0; for (int j = 0; j < i; ++j) if (sgn(dis(p[j], c)-r)>0) { c.x = (p[i].x+p[j].x)/2; c.y = (p[i].y+p[j].y)/2; r = dis(p[j], c); for (int k = 0; k < j; ++k) if (sgn(dis(p[k], c)-r)>0) { concylic(p[i], p[j], p[k], c, r); r = dis(p[i], c); } } } }
/* Project: Biribiri Standard Code Library [BSCL] Author: [BUPT]Biribiri Category: Geometry Title: Rotating Calipers Version: 0.314 Date: 2011/2/6 Remark: N/A Tested Problems: N/A Tag: geometry, rotating calipers Special Thanks: Amber */ /* Input: A convex hull by counterclockwise Output: The maximum distance of pairs of points */ #include <cstdio> #include <cmath> #include <algorithm> using namespace std; const double INF = 1e9; const double EPS = 1e-8; const double PI = acos(-1.0); inline int sgn(double d) { if (fabs(d) < EPS) return 0; return d>0 ? 1 : -1; } struct sp { double x, y; double dis, ang; sp() {} sp(double xx, double yy): x(xx), y(yy) {} void read() {scanf("%lf%lf", &x, &y);} }; sp operator - (const sp &v1, const sp &v2) {return sp(v1.x-v2.x, v1.y-v2.y);} double det(const sp &u, const sp &v) {return u.x*v.y - v.x*u.y;} double dis(const sp &u, const sp &v) { double dx = u.x-v.x; double dy = u.y-v.y; return sqrt(dx*dx+dy*dy); } double dir(const sp &p, const sp &u, const sp &v) {return det(u-p, v-p);} double rotatingcalipers(int N, sp poly[]) { poly[N] = poly[0]; int p=0, q=1; double ans = 0; for (; p < N; ++p) { //p, q即对踵点 //此处根据不同的需求改卡壳函数 while (sgn(dir(poly[p], poly[p+1], poly[q+1])-dir(poly[p], poly[p+1], poly[q])) > 0) q = (q+1) % N; ans = max(ans, max(dis(poly[p], poly[q]), dis(poly[p+1], poly[q+1]))); } return ans; } /* begin p0:=pn; q:=NEXT[p]; while (Area(p,NEXT[p],NEXT[q]) > Area(p,NEXT[p],q)) do q:=NEXT[q]; q0:=q; while (q != p0) do begin p:=NEXT[p]; Print(p,q); while (Area(p,NEXT[p],NEXT[q]) > Area(p,NEXT[p],q) do begin q:=NEXT[q]; if ((p,q) != (q0,p0)) then Print(p,q) else return end; if (Area(p,NEXT[p],NEXT[q]) = Area(p,NEXT[p],q)) then if ((p,q) != (q0,p0)) then Print(p,NEXT[q]) else Print(NEXT[p],q) end end. */