二维几何模版

转自: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

凸包(graham)
/* 
    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. 
 */




你可能感兴趣的:(Algorithm,c,Date,struct,include,library)