暑假集训 || 计算几何

看起来很挫的……

 

线段与直线

const int SZ = 150;
const int INF = 1e9+10;
const double eps = 1e-8;
const double pi = acos(-1.0);
int sgn(double x)
{
    if(fabs(x) < eps) return 0;
    if(x < 0) return -1;
    return 1;
}
struct Point
{
    double x, y;
    Point () {}
    Point (double x, double y) : x(x), y(y) {}
    Point operator +(const Point &a)const{
        return Point(x + a.x, y + a.y);
    }
    Point operator -(const Point &a)const{
        return Point(x - a.x, y - a.y);
    }
    bool operator ==(const Point &a)const{
        if(sgn(x - a.x) == 0 && sgn(y - a.y) == 0) return true;
        return false;
    }
    bool operator !=(const Point &a)const{
        return x != a.x || y != a.y;
    }
    bool operator <(const Point &a)const{
        if(a.x != x) return x < a.x;//以x作为第一关键字排序
        return y < a.y;
    }
    double operator *(const Point &a)const{//点乘
        return x * a.x + y * a.y;
    }
    double operator ^(const Point &a)const{//叉乘
        return x * a.y - y * a.x;
    }
}p[SZ];
struct edge
{
    Point s, e;
}line[SZ];
double xmul(Point a, Point b, Point c) //ab * ac, xmul<0表示p0在se左
{
    return (b - a) ^ (c - a);
}
double getdis(Point a, Point b)//点a与点b之间的距离
{
    return sqrt((a-b) * (a-b));
}
bool online(Point p, edge l)//p是否在线段l上
{
    return sgn((p-l.s) ^ (l.e-l.s)) == 0 && sgn((p-l.s) * (p-l.e)) <= 0;
}
bool checkcross(edge l1, edge l2)//判断直线l1是否与线段l2相交
{
    if(sgn(xmul(l2.s, l1.s, l1.e)) * sgn(xmul(l2.e, l1.s, l1.e)) <= 0) return true;
    return false;
}
bool onseg(edge l1, edge l2)//判断线段l1是否与线段l2共线但不重合
{
    int flag = 0;
    if(max(l1.s.x, l1.e.x) < min(l2.s.x, l2.e.x) || max(l2.s.x, l2.e.x) < min(l1.s.x, l1.e.x)) flag++;
    if(max(l1.s.y, l1.e.y) < min(l2.s.y, l2.e.y) || max(l2.s.y, l2.e.y) < min(l1.s.y, l1.e.y)) flag++;
    if(getk(l1.s, l1.e) - getk(l2.s, l2.e) == 0) flag++;
    if(flag == 3) return true;
    return false;
}
bool checksegcross(edge l1, edge l2)//判断线段l1是否与线段l2相交
{
    int flag = 0;
    if(((l2.e-l2.s) ^ (l1.s-l2.s)) * ((l2.e-l2.s) ^ (l1.e-l2.s)) <= 0) flag++;
    if(((l1.e-l1.s) ^ (l2.s-l1.s)) * ((l1.e-l1.s) ^ (l2.e-l1.s)) <= 0) flag++;
    if(!onseg(a, b)) flag++;
    if(flag == 3) return true;
    return false;
}
View Code

 

 

求凸包:

bool cmp(Point a, Point b)
{
    double tmp = xmul(p[0], a, b);
    if(sgn(tmp) < 0) return false;
    if(sgn(tmp) > 0) return true;
    return getdis(p[0], a) < getdis(p[0], b);
}
int n;
double graham()
{
    int k = 0;
    for(int i = 1; i < n; i++)
        if(p[i].y < p[k].y || (p[i].y == p[k].y && p[i].x < p[k].x)) k = i;
    swap(p[0], p[k]);
    sort(p+1, p+n, cmp);
    int top = 0;
    s[top++] = p[0]; s[top++] = p[1];
    for(int i = 2;i < n;i ++)
    {
        while(top > 1 && ((s[top-1] - s[top-2]) ^ (p[i] - s[top-2])) < 0)
            top --;
        s[top++] = p[i];
    }
    double ans = 0;
    for(int i = 0; i < top; i++)
        ans += getdis(s[i], i == top-1 ? s[0] : s[i+1]);
    return ans;
}
View Code

 

POJ 1113

用墙围起来,墙距离原图形至少L距离

就是凸包的周长加上一个半径为L的圆

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
using namespace std;
const int SZ = 1100;
const int INF = 1e9+10;
const double eps = 1e-8;
const double pi = acos(-1.0);
int sgn(double x)
{
    if(fabs(x) < eps) return 0;
    if(x < 0) return -1;
    return 1;
}
struct Point
{
    double x, y;
    Point operator +(const Point &a)const{
        return (Point){a.x + x, a.y + y};
    }
    Point operator -(const Point &a)const{
        return (Point){a.x - x, a.y - y};
    }
    bool operator ==(const Point &a)const{
        if(sgn(a.x - x) == 0 && sgn(a.y - y) == 0) return true;
        return false;
    }
    bool operator !=(const Point &a)const{
        return a.x != x || a.y != y;
    }
    bool operator <(const Point &a)const{
        if(a.x != x) return a.x < x;
        return a.y < y;
    }
    double operator *(const Point &a)const{
        return a.x * x + a.y * y;
    }
    double operator ^(const Point &a)const{
        return a.x * y - a.y * x;
        //return x * a.y - y * a.x;
    }
}p[SZ], s[SZ];
double xmul(Point p0, Point p1, Point p2) //p0p1 * p0p2 xmul<0 p0在p1p2左
{
    return (p1 - p0) ^ (p2 - p0);
}
double getdis(Point a, Point b)
{
    return sqrt((a-b) * (a-b));
}
bool cmp(Point a, Point b)
{
    double tmp = xmul(p[0], a, b);
    if(sgn(tmp) < 0) return false;
    if(sgn(tmp) > 0) return true;
    return getdis(p[0], a) < getdis(p[0], b);
}
int n;
double graham()
{
    int k = 0;
    for(int i = 1; i < n; i++)
        if(p[i].y < p[k].y || (p[i].y == p[k].y && p[i].x < p[k].x)) k = i;
    swap(p[0], p[k]);
    sort(p+1, p+n, cmp);
    int top = 0;
    s[top++] = p[0]; s[top++] = p[1];
    for(int i = 2;i < n;i ++)
    {
        while(top > 1 && ((s[top-1] - s[top-2]) ^ (p[i] - s[top-2])) < 0)
            top --;
        s[top++] = p[i];
    }
    double ans = 0;
    for(int i = 0; i < top; i++)
        ans += getdis(s[i], i == top-1 ? s[0] : s[i+1]);
    return ans;
}
int main()
{
    int L;
    scanf("%d %d", &n, &L);
    for(int i = 0; i < n; i++)
    {
        int a, b;
        scanf("%d %d", &a, &b);
        p[i] = (Point){a, b};
    }
    double ans = graham();
    ans += pi * 2 * L;
    printf("%.0f\n", ans);
    return 0;
}
View Code

 

POJ 1696

题意:只能直走或者左转,最多能到达多少个点

思路:合理选择出发点肯定每个点都能到达,贪心的思想

每次选以上一个位置为极点,极角最小的点。

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <cmath>
 5 #include <algorithm>
 6 #include <queue>
 7 using namespace std;
 8 const int SZ = 150;
 9 const int INF = 1e9+10;
10 const double eps = 1e-8;
11 const double pi = acos(-1.0);
12 int sgn(double x)
13 {
14     if(fabs(x) < eps) return 0;
15     if(x < 0) return -1;
16     return 1;
17 }
18 struct Point
19 {
20     int id;
21     double x, y;
22     Point operator -(const Point &a)const{
23         return (Point){id, x - a.x, y - a.y};
24     }
25     double operator *(const Point &a)const{
26         return a.x * x + a.y * y;
27     }
28     double operator ^(const Point &b)const
29     {
30         return x*b.y - y*b.x;
31     }
32 }p[SZ];
33 double xmul(Point p0, Point p1, Point p2) //p0p1 * p0p2 xmul<0 p0在p1p2左
34 {
35     return (p1 - p0) ^ (p2 - p0);
36 }
37 double getdis(Point a, Point b)
38 {
39     return sqrt((a-b) * (a-b));
40 }
41 int idx;//标记上一个位置 为极点
42 bool cmp(Point a, Point b)
43 {
44     double tmp = xmul(p[idx], a, b);
45     if(sgn(tmp) < 0) return false;
46     if(sgn(tmp) > 0) return true;
47     return getdis(p[idx], a) < getdis(p[idx], b);
48 }
49 int main()
50 {
51     int T;
52     scanf("%d", &T);
53     while(T--)
54     {
55         int n, id;
56         scanf("%d", &n);
57         for(int i = 1; i <= n; i++)
58             scanf("%d %lf %lf", &p[i].id, &p[i].x, &p[i].y);
59         int k = 1;
60         for(int i = 2; i <= n; i++)
61             if(p[i].y < p[k].y || (p[i].y == p[k].y && p[i].x < p[k].x)) k = i;
62         swap(p[1], p[k]);
63         idx = 1;
64         for(int i = 2; i <= n; i++)
65         {
66             sort(p+i, p+1+n, cmp);
67             idx++;
68         }
69         printf("%d", n);
70         for(int i = 1; i <= n; i++)
71             printf(" %d", p[i].id);
72         printf("\n");
73     }
74     return 0;
75 }
View Code

 

HDU 6325

题意:每个点有一个标号,要求x坐标递增,代价为两个坐标的叉积。 求起点到终点总代价最小的飞行路线,并输出字典序最小的路线

思路:因为凸包是求逆时针的时候面积包住所有点的面积最大,那么我们题目这样是顺时针,相反的就是面积最小,所以这题就是求顺时针的凸包,那肯定就包括起点、终点、凸包的拐点了,只要把上凸包求出来就好

就是改一下cmp和求凸包的时候的更新函数

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
using namespace std;
const int SZ = 200200;
const int INF = 1e9+10;
const double eps = 1e-8;
const double pi = acos(-1.0);
#define getT int T;scanf("%d", &T); while(T--)
int sgn(double x)
{
    if(fabs(x) < eps) return 0;
    if(x < 0) return -1;
    return 1;
}
struct Point
{
    double x, y;
    int id;
    Point () {}
    Point (double x, double y) : x(x), y(y) {}
    Point operator -(const Point &a)const{
        return (Point){x - a.x, y - a.y};
    }
    double operator *(const Point &a)const{//点乘
        return x * a.x + y * a.y;
    }
    double operator ^(const Point &a)const{//叉乘
        return x * a.y - y * a.x;
    }
}p[SZ];
double xmul(Point a, Point b, Point c) //ab * ac, xmul<0表示p0在se左
{
    return (b - a) ^ (c - a);
}
int n;
bool cmp(Point a, Point b)
{
    if(a.x != b.x) return a.x < b.x;
    return a.id > b.id;
}
int top;
int s[SZ];
void graham()
{
    top = 0;
    sort(p+1, p+n+1, cmp);
    s[++top] = 1; s[++top] = 2;
    for(int i = 3; i <= n; i++)
    {
        while(top > 1)
        {
            int x = s[top]; top--;
            int y = s[top];
            if(xmul(p[y], p[i], p[x]) > 0 || (xmul(p[y], p[i], p[x]) == 0 && p[i].id > p[x].id))
            {
                s[++top] = x;
                break;
            }
        }
        s[++top] = i;
    }
}
int main()
{
    getT
    {
        scanf("%d", &n);
        for(int i = 1; i <= n; i++)
        {
            double x, y;
            scanf("%lf %lf", &x, &y);
            p[i] = Point(x, y);
            p[i].id = i;
        }
        graham();
        printf("%d", p[s[1]].id);
        for(int i = 2; i <= top; i++)
            printf(" %d", p[s[i]].id);
        printf("\n");
    }
    return 0;
}
View Code

 

BZOJ 1007

给出n条形如y = kx + b的直线,求从y轴正无穷向下看能看到哪些直线

 

 

·三维凸包

HDU 3662 模板。。很强

#include <iostream>
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
using namespace std;
const int SZ = 320;
const int INF = 1e9+10;
const double eps = 1e-8;
const double pi = acos(-1.0);
int sgn(double x)
{
    if(fabs(x) < eps) return 0;
    if(x < 0) return -1;
    return 1;
}
struct Point
{
    double x, y, z;
    Point () {}
    Point (double x, double y, double z) : x(x), y(y), z(z) {}
    Point operator -(const Point &a)const{
        return Point(x - a.x, y - a.y, z - a.z);
    }
    double operator *(const Point &a)const{//点乘
        return x * a.x + y * a.y + z * a.z;
    }
    Point operator ^(const Point &a)const{//叉乘
        return Point(y * a.z - z * a.y, z * a.x - x * a.z, x * a.y - y * a.x);
    }
}p[SZ];
Point xmul(Point a, Point b, Point c) //ab * ac, xmul<0表示p0在se左
{
    return (b - a) ^ (c - a);
}
double getdis(Point a, Point b)//点a与点b之间的距离
{
    return sqrt((a-b) * (a-b));
}
double getlen(Point a)
{
    return a.x*a.x + a.y*a.y + a.z*a.z;
}
struct Face
{
    int a, b, c;
    bool flag;
} face;
struct CH3D
{
    struct face
    {
        int a,b,c;//表示凸包一个面上三个点的编号
        bool flag;//表示该面是否属于最终凸包中的面
    };

    int n; //初始顶点数
    Point P[SZ]; //初始顶点

    int num; //凸包表面的三角形数
    face F[8*SZ];//凸包表面的三角形

    int g[SZ][SZ];

    Point cross(const Point &a, const Point &b, const Point &c)
    {
        return (b-a) ^ (c-a);
    }
    double area(Point a,Point b,Point c) //三角形面积*2
    {
        return getlen((b-a) ^ (c-a));
    }

    double volume(Point a,Point b,Point c,Point d) //四面体有向体积*6
    {
        return ((b-a) ^ (c-a)) * (d-a);
    }

    double dblcmp(Point &p,face &f) //正:点在面同向
    {
        Point p1 = P[f.b]-P[f.a];
        Point p2 = P[f.c]-P[f.a];
        Point p3 = p-P[f.a];
        return (p1 ^ p2) * p3;
    }

    void deal(int p,int a,int b)
    {
        int f = g[a][b];
        face add;
        if(F[f].flag)
        {
            if(dblcmp(P[p], F[f]) > eps)
                dfs(p, f);
            else
            {
                add.a = b;
                add.b = a;
                add.c = p;
                add.flag = 1;
                g[p][b] = g[a][p] = g[b][a] = num;
                F[num++] = add;
            }
        }
    }

    void dfs(int p,int now) //递归搜索所有应该从凸包内删除的面
    {
        F[now].flag = false;
        deal(p,F[now].b,F[now].a);
        deal(p,F[now].c,F[now].b);
        deal(p,F[now].a,F[now].c);
    }

    bool same(int s,int t)
    {
        Point &a = P[F[s].a];
        Point &b = P[F[s].b];
        Point &c = P[F[s].c];
        return fabs(volume(a,b,c,P[F[t].a])) < eps && fabs(volume(a,b,c,P[F[t].b])) < eps && fabs(volume(a,b,c,P[F[t].c])) < eps;
    }

    void create() //构建三维凸包
    {
        int i, j, tmp;
        face add;
        bool flag = true;
        num = 0;
        if(n < 4)
            return;
        for(i = 1; i < n; i++) //此段是为了保证前四个点不共面
        {
            if(getlen(P[0] - P[i]) > eps)
            {
                swap(P[1], P[i]);
                flag = false;
                break;
            }
        }
        if(flag)
            return;
        flag = true;
        for(i = 2; i < n; i++) //使前三点不共线
        {
            if(getlen((P[0]-P[1]) ^ (P[1]-P[i])) > eps)
            {
                swap(P[2], P[i]);
                flag = false;
                break;
            }
        }
        if(flag)
            return;
        flag = true;
        for(i = 3; i < n; i++) //使前四点不共面
        {
            if(fabs(((P[1]-P[0]) ^ (P[2]-P[0])) * (P[i]-P[0])) > eps)
            {
                swap(P[3], P[i]);
                flag = false;
                break;
            }
        }
        if(flag)
            return;
        for(i = 0; i < 4; i++)
        {
            add.a = (i+1)%4;
            add.b = (i+2)%4;
            add.c = (i+3)%4;
            add.flag = true;
            if(dblcmp(P[i],add) > 0)
                swap(add.b, add.c);
            g[add.a][add.b] = g[add.b][add.c] = g[add.c][add.a] = num;
            F[num++] = add;
        }
        for(i = 4; i < n; i++)
        {
            for(j = 0; j < num; j++)
            {
                if(F[j].flag && dblcmp(P[i],F[j]) > eps)
                {
                    dfs(i,j);
                    break;
                }
            }
        }
        tmp = num;
        for(i = num = 0; i<tmp; i++)
            if(F[i].flag)
            {
                F[num++] = F[i];
            }
    }

    double area() //表面积
    {
        double res = 0.0;
        if(n == 3)
        {
            Point p = cross(P[0],P[1],P[2]);
            res = getlen(p) / 2.0;
            return res;
        }
        for(int i = 0; i < num; i++)
            res += area(P[F[i].a],P[F[i].b],P[F[i].c]);
        return res/2.0;
    }

    double volume() //体积
    {
        double res = 0.0;
        Point tmp(0,0,0);
        for(int i = 0; i<num; i++)
            res += volume(tmp,P[F[i].a],P[F[i].b],P[F[i].c]);
        return fabs(res/6.0);
    }

    int triangle() //表面三角形个数
    {
        return num;
    }

    int polygon() //表面多边形个数
    {
        int i,j,res = 0,flag;
        for(i = 0; i < num; i++)
        {
            flag = 1;
            for(j = 0; j < i; j++)
                if(same(i,j))
                {
                    flag = 0;
                    break;
                }
            res += flag;
        }
        return res;
    }
    Point getcenter()//求凸包质心
    {
        Point ans(0,0,0),temp = P[F[0].a];
        double v  =  0.0,t2;
        for(int i = 0; i < num; i++)
        {
            if(F[i].flag == true)
            {
                Point p1 = P[F[i].a],p2 = P[F[i].b],p3 = P[F[i].c];
                t2 = volume(temp,p1,p2,p3)/6.0;//体积大于0,也就是说,点 temp 不在这个面上
                if(t2 > 0)
                {
                    ans.x += (p1.x+p2.x+p3.x+temp.x)*t2;
                    ans.y += (p1.y+p2.y+p3.y+temp.y)*t2;
                    ans.z += (p1.z+p2.z+p3.z+temp.z)*t2;
                    v += t2;
                }
            }
        }
        ans.x /= (4*v);
        ans.y /= (4*v);
        ans.z /= (4*v);
        return ans;
    }
    double function(Point pp) //点到凸包上的最近距离(枚举每个面到这个点的距离)
    {
        double min = INF;
        for(int i = 0; i<num; i++)
        {
            if(F[i].flag == true)
            {
                Point p1 = P[F[i].a] , p2 = P[F[i].b] , p3 = P[F[i].c];
                double a = ( (p2.y-p1.y)*(p3.z-p1.z)-(p2.z-p1.z)*(p3.y-p1.y) );
                double b = ( (p2.z-p1.z)*(p3.x-p1.x)-(p2.x-p1.x)*(p3.z-p1.z) );
                double c = ( (p2.x-p1.x)*(p3.y-p1.y)-(p2.y-p1.y)*(p3.x-p1.x) );
                double d = ( 0-(a*p1.x+b*p1.y+c*p1.z) );
                double temp = fabs(a*pp.x+b*pp.y+c*pp.z+d)/sqrt(a*a+b*b+c*c);
                if(temp < min)min = temp;
            }
        }
        return min;
    }

};
CH3D hull;
int main()
{
    while(~scanf("%d", &hull.n))
    {
        for(int i = 0; i < hull.n; i++)
        {
            double x, y, z;
            scanf("%lf %lf %lf", &x, &y, &z);
            hull.P[i] = Point(x, y, z);
        }
        hull.create();
        printf("%d\n", hull.polygon());
    }
    return 0;
}
View Code

 

 

·旋转卡壳

求平面内的点之间的最长距离

模板:

bool cmp(Point a, Point b)
{
    double tmp = xmul(p[0], a, b);
    if(sgn(tmp) > 0 || (sgn(tmp) == 0 && getdis(p[0], a) > getdis(p[0], b))) return true;
    return false;
}
int top;
void graham()
{
    int k = 0;
    top = 0;
    for(int i = 1; i < n; i++)
        if(p[i].y < p[k].y || (p[i].y == p[k].y && p[i].x < p[k].x)) k = i;
    swap(p[0], p[k]);
    sort(p+1, p+n, cmp);
    s[top++] = p[0]; s[top++] = p[1];
    for(int i = 2;i < n;i ++)
    {
        while(top > 1 && xmul(s[top-2], s[top-1], p[i]) < 0)
            top --;
        s[top++] = p[i];
    }
}
int RC()
{
    s[top] = s[0];
    int now = 1, ans = 0;
    for(int i = 0; i < top; i++)
    {
        while(xmul(s[i], s[i+1], s[now]) < xmul(s[i], s[i+1], s[now+1]))
        {
            now++;
            if(now == top) now = 0;
        }
        ans = max(ans, max(getdis(s[now], s[i]), getdis(s[now], s[i+1])));
    }
    return ans;
}
View Code

 

 

·半平面交

/*半平面相交(直线切割多边形)(点标号从1开始)*/  
Point points[MAXN],p[MAXN],q[MAXN];  
int n;  
double r;  
int cCnt,curCnt;  
inline void getline(Point x,Point y,double &a,double &b,double &c){  
    a = y.y - x.y;  
    b = x.x - y.x;  
    c = y.x * x.y - x.x * y.y;  
}  
inline void initial(){  
    for(int i = 1; i <= n; ++i)p[i] = points[i];  
    p[n+1] = p[1];  
    p[0] = p[n];  
    cCnt = n;  
}  
inline Point intersect(Point x,Point y,double a,double b,double c){  
    double u = fabs(a * x.x + b * x.y + c);  
    double v = fabs(a * y.x + b * y.y + c);  
    return Point( (x.x * v + y.x * u) / (u + v) , (x.y * v + y.y * u) / (u + v) );  
}  
inline void cut(double a,double b ,double c){  
    curCnt = 0;  
    for(int i = 1; i <= cCnt; ++i){  
        if(a*p[i].x + b*p[i].y + c >= EPS)q[++curCnt] = p[i];  
        else {  
            if(a*p[i-1].x + b*p[i-1].y + c > EPS){  
                q[++curCnt] = intersect(p[i],p[i-1],a,b,c);  
            }  
            if(a*p[i+1].x + b*p[i+1].y + c > EPS){  
                q[++curCnt] = intersect(p[i],p[i+1],a,b,c);  
            }  
        }  
    }  
    for(int i = 1; i <= curCnt; ++i)p[i] = q[i];  
    p[curCnt+1] = q[1];p[0] = p[curCnt];  
    cCnt = curCnt;  
}  
inline void solve(){  
    //注意:默认点是顺时针,如果题目不是顺时针,规整化方向  
    initial();  
    for(int i = 1; i <= n; ++i){  
        double a,b,c;  
        getline(points[i],points[i+1],a,b,c);  
        cut(a,b,c);  
    }  
    /* 
    如果要向内推进r,用该部分代替上个函数 
    for(int i = 1; i <= n; ++i){ 
        Point ta, tb, tt; 
        tt.x = points[i+1].y - points[i].y; 
        tt.y = points[i].x - points[i+1].x; 
        double k = r / sqrt(tt.x * tt.x + tt.y * tt.y); 
        tt.x = tt.x * k; 
        tt.y = tt.y * k; 
        ta.x = points[i].x + tt.x; 
        ta.y = points[i].y + tt.y; 
        tb.x = points[i+1].x + tt.x; 
        tb.y = points[i+1].y + tt.y; 
        double a,b,c; 
        getline(ta,tb,a,b,c); 
        cut(a,b,c); 
    } 
    */  
    //多边形核的面积  
    double area = 0;  
    for(int i = 1; i <= curCnt; ++i)  
        area += p[i].x * p[i + 1].y - p[i + 1].x * p[i].y;  
    area = fabs(area / 2.0);  
    //此时cCnt为最终切割得到的多边形的顶点数,p为存放顶点的数组  
}  
inline void GuiZhengHua(){  
     //规整化方向,逆时针变顺时针,顺时针变逆时针  
    for(int i = 1; i < (n+1)/2; i ++)  
      swap(points[i], points[n-i]);//头文件加iostream  
}  
inline void init(){  
     for(int i = 1; i <= n; ++i)points[i].input();  
        points[n+1] = points[1];  
}
View Code

 

 

裸题:POJ 2187

求n个点之间的最长距离的平方

  1 #include <iostream>
  2 #include <iostream>
  3 #include <cstdio>
  4 #include <cstring>
  5 #include <cmath>
  6 #include <algorithm>
  7 #include <queue>
  8 using namespace std;
  9 const int SZ = 50200;
 10 const int INF = 1e9+10;
 11 const double eps = 1e-8;
 12 const double pi = acos(-1.0);
 13 using namespace std;
 14 int sgn(double x)
 15 {
 16     if(fabs(x) < eps) return 0;
 17     if(x < 0) return -1;
 18     return 1;
 19 }
 20 struct Point
 21 {
 22     double x, y;
 23     Point () {}
 24     Point (double x, double y) : x(x), y(y) {}
 25     Point operator +(const Point &a)const{
 26         return (Point){x + a.x, y + a.y};
 27     }
 28     Point operator -(const Point &a)const{
 29         return (Point){x - a.x, y - a.y};
 30     }
 31     bool operator ==(const Point &a)const{
 32         if(sgn(x - a.x) == 0 && sgn(y - a.y) == 0) return true;
 33         return false;
 34     }
 35     bool operator !=(const Point &a)const{
 36         return x != a.x || y != a.y;
 37     }
 38     bool operator <(const Point &a)const{
 39         if(a.x != x) return x < a.x;//以x作为第一关键字排序
 40         return y < a.y;
 41     }
 42     double operator *(const Point &a)const{//点乘
 43         return x * a.x + y * a.y;
 44     }
 45     double operator ^(const Point &a)const{//叉乘
 46         return x * a.y - y * a.x;
 47     }
 48 }p[SZ], s[SZ];
 49 double xmul(Point a, Point b, Point c) //ab * ac, xmul<0表示p0在se左
 50 {
 51     return (b - a) ^ (c - a);
 52 }
 53 int getdis(Point a, Point b)//点a与点b之间的距离
 54 {
 55     return (a-b) * (a-b);
 56 }
 57 int n;
 58 bool cmp(Point a, Point b)
 59 {
 60     double tmp = xmul(p[0], a, b);
 61     if(sgn(tmp) > 0 || (sgn(tmp) == 0 && getdis(p[0], a) > getdis(p[0], b))) return true;
 62     return false;
 63 }
 64 int top;
 65 void graham()
 66 {
 67     int k = 0;
 68     top = 0;
 69     for(int i = 1; i < n; i++)
 70         if(p[i].y < p[k].y || (p[i].y == p[k].y && p[i].x < p[k].x)) k = i;
 71     swap(p[0], p[k]);
 72     sort(p+1, p+n, cmp);
 73     s[top++] = p[0]; s[top++] = p[1];
 74     for(int i = 2;i < n;i ++)
 75     {
 76         while(top > 1 && xmul(s[top-2], s[top-1], p[i]) < 0)
 77             top --;
 78         s[top++] = p[i];
 79     }
 80 }
 81 int RC()
 82 {
 83     s[top] = s[0];
 84     int now = 1, ans = 0;
 85     for(int i = 0; i < top; i++)
 86     {
 87         while(xmul(s[i], s[i+1], s[now]) < xmul(s[i], s[i+1], s[now+1]))
 88         {
 89             now++;
 90             if(now == top) now = 0;
 91         }
 92         ans = max(ans, max(getdis(s[now], s[i]), getdis(s[now], s[i+1])));
 93     }
 94     return ans;
 95 }
 96 int main()
 97 {
 98     scanf("%d", &n);
 99     for(int i = 0; i < n; i++)
100     {
101         double x, y;
102         scanf("%lf %lf", &x, &y);
103         p[i] = Point(x, y);
104     }
105     graham();
106     printf("%d\n", RC());
107     return 0;
108 }
View Code

 

 

·半平面交

模板:

 1 /*半平面相交(直线切割多边形)(点标号从1开始)*/
 2 Point points[SZ],p[SZ],q[SZ];
 3 int n;
 4 double r;
 5 int cCnt,curCnt;
 6 inline void getline(Point x,Point y,double &a,double &b,double &c)
 7 {
 8     a = y.y - x.y;
 9     b = x.x - y.x;
10     c = y.x * x.y - x.x * y.y;
11 }
12 inline void initial()
13 {
14     for(int i = 1; i <= n; ++i) p[i] = points[i];
15     p[n+1] = p[1];
16     p[0] = p[n];
17     cCnt = n;
18 }
19 inline Point intersect(Point x,Point y,double a,double b,double c)
20 {
21     double u = fabs(a * x.x + b * x.y + c);
22     double v = fabs(a * y.x + b * y.y + c);
23     return Point( (x.x * v + y.x * u) / (u + v) , (x.y * v + y.y * u) / (u + v) );
24 }
25 inline void cut(double a,double b ,double c)
26 {
27     curCnt = 0;
28     for(int i = 1; i <= cCnt; ++i)
29     {
30         if(a*p[i].x + b*p[i].y + c >= eps)q[++curCnt] = p[i];
31         else
32         {
33             if(a*p[i-1].x + b*p[i-1].y + c > eps)
34             {
35                 q[++curCnt] = intersect(p[i],p[i-1],a,b,c);
36             }
37             if(a*p[i+1].x + b*p[i+1].y + c > eps)
38             {
39                 q[++curCnt] = intersect(p[i],p[i+1],a,b,c);
40             }
41         }
42     }
43     for(int i = 1; i <= curCnt; ++i)p[i] = q[i];
44     p[curCnt+1] = q[1];
45     p[0] = p[curCnt];
46     cCnt = curCnt;
47 }
48 inline void solve()
49 {
50     //注意:默认点是顺时针,如果题目不是顺时针,规整化方向
51     initial();
52     for(int i = 1; i <= n; ++i)
53     {
54         double a,b,c;
55         getline(points[i],points[i+1],a,b,c);
56         cut(a,b,c);
57     }
58     /*
59     如果要向内推进r,用该部分代替上个函数
60     for(int i = 1; i <= n; ++i){
61         Point ta, tb, tt;
62         tt.x = points[i+1].y - points[i].y;
63         tt.y = points[i].x - points[i+1].x;
64         double k = r / sqrt(tt.x * tt.x + tt.y * tt.y);
65         tt.x = tt.x * k;
66         tt.y = tt.y * k;
67         ta.x = points[i].x + tt.x;
68         ta.y = points[i].y + tt.y;
69         tb.x = points[i+1].x + tt.x;
70         tb.y = points[i+1].y + tt.y;
71         double a,b,c;
72         getline(ta,tb,a,b,c);
73         cut(a,b,c);
74     }
75     */
76     //多边形核的面积
77     double area = 0;
78     for(int i = 1; i <= curCnt; ++i)
79         area += p[i].x * p[i + 1].y - p[i + 1].x * p[i].y;
80     area = fabs(area / 2.0);
81     //此时cCnt为最终切割得到的多边形的顶点数,p为存放顶点的数组
82 }
83 inline void GuiZhengHua()
84 {
85     //规整化方向,逆时针变顺时针,顺时针变逆时针
86     for(int i = 1; i < (n+1)/2; i ++)
87         swap(points[i], points[n-i]);//头文件加iostream
88 }
89 inline void init()
90 {
91     scanf("%d", &n);
92     for(int i = 1; i <= n; ++i)
93     {
94         double x, y;
95         scanf("%lf %lf", &x, &y);
96         points[i] = Point(x, y);
97     }
98     points[n+1] = points[1];
99 }
View Code

 

·圆交多边形

模板:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
using namespace std;
const int SZ = 520;
const int INF = 1e9+10;
const double eps = 1e-8;
const double pi = acos(-1.0);
int n;
int sgn(double x)
{
    if(fabs(x) < eps) return 0;
    if(x < 0) return -1;
    return 1;
}
struct Point
{
    double x, y;
    Point () {}
    Point (double x, double y) : x(x), y(y) {}
    Point operator +(const Point &a)const{
        return Point(x + a.x, y + a.y);
    }
    Point operator -(const Point &a)const{
        return Point(x - a.x, y - a.y);
    }
    bool operator ==(const Point &a)const{
        if(sgn(x - a.x) == 0 && sgn(y - a.y) == 0) return true;
        return false;
    }
    bool operator !=(const Point &a)const{
        return x != a.x || y != a.y;
    }
    bool operator <(const Point &a)const{
        if(a.x != x) return x < a.x;//以x作为第一关键字排序
        return y < a.y;
    }
    double operator *(const Point &a)const{//点乘
        return x * a.x + y * a.y;
    }
    double operator ^(const Point &a)const{//叉乘
        return x * a.y - y * a.x;
    }
    double sqrx() //向量的模
    {
        return sqrt(x*x+y*y);
    }
}p[SZ], A, B;
double xmult(Point a, Point b, Point c) //ab * ac, xmul<0表示p0在se左
{
    return (b - a) ^ (c - a);
}
double getsqrtdis(Point a, Point b)//点a与点b之间的距离
{
    return sqrt((a-b) * (a-b));
}
double getdis(Point a, Point b)
{
    return (a-b) * (a-b);
}
Point crossline(Point u1, Point v1, Point u2, Point v2)//直线u1v1与直线u2v2的交点
{
    double a1 = (v2 - u2) ^ (u1 - u2);
    double a2 = (v2 - u2) ^ (v1 - u2);
    return Point( (u1.x*a2 - v1.x*a1) / (a2 - a1), (u1.y*a2 - v1.y*a1) / (a2 - a1) );
}
void intersection_line_circle(Point c,double r,Point l1,Point l2,Point& p1,Point& p2){
    Point p=c;
    double t;
    p.x+=l1.y-l2.y;
    p.y+=l2.x-l1.x;
    p=crossline(p,c,l1,l2);
    t=sqrt(r*r-getsqrtdis(p,c)*getsqrtdis(p,c))/getsqrtdis(l1,l2);
    p1.x=p.x+(l2.x-l1.x)*t;
    p1.y=p.y+(l2.y-l1.y)*t;
    p2.x=p.x-(l2.x-l1.x)*t;
    p2.y=p.y-(l2.y-l1.y)*t;
}
Point ptoseg(Point p,Point l1,Point l2)            //点到线段的最近距离
{
    Point t=p;
    t.x+=l1.y-l2.y,t.y+=l2.x-l1.x;
    if (xmult(l1,t,p)*xmult(l2,t,p)>eps)
    return getsqrtdis(p,l1)<getsqrtdis(p,l2)?l1:l2;
    return crossline(p,t,l1,l2);
}
struct Circle
{
    Point c;
    double r;
    Circle() {}
    Circle(Point c, double r) : c(c), r(r) {}
}C;
 double Triangle_Circle_Area(Point a,Point b,Point o,double r)
{
    double sign=1.0;
    a=a-o;
    b=b-o;
    o=Point(0.0,0.0);
    if(fabs(xmult(a,b,o))<eps) return 0.0;
    if(getdis(a,o)>getdis(b,o))
    {
        swap(a,b);
        sign=-1.0;
    }
    if(getdis(a,o)<r*r+eps)
    {
        if(getdis(b,o)<r*r+eps) return xmult(a,b,o)/2.0*sign;
        Point p1,p2;
        intersection_line_circle(o,r,a,b,p1,p2);
        if(getsqrtdis(p1,b)>getsqrtdis(p2,b)) swap(p1,p2);
        double ret1=fabs(xmult(a,p1,o));
        double ret2=acos( p1*b/p1.sqrx()/b.sqrx() )*r*r;
        double ret=(ret1+ret2)/2.0;
        if(xmult(a,b,o)<eps && sign>0.0 || xmult(a,b,o)>eps && sign<0.0) ret=-ret;
        return ret;
    }
    Point ins=ptoseg(o,a,b);
    if(getdis(o,ins)>r*r-eps)
    {
        double ret=acos( a*b/a.sqrx()/b.sqrx() )*r*r/2.0;
        if(xmult(a,b,o)<eps && sign>0.0 || xmult(a,b,o)>eps && sign<0.0) ret=-ret;
        return ret;
    }
    Point p1,p2;
    intersection_line_circle(o,r,a,b,p1,p2);
    double cm=r/(getsqrtdis(o,a)-r);
    Point m=Point( (o.x+cm*a.x)/(1+cm) , (o.y+cm*a.y)/(1+cm) );
    double cn=r/(getsqrtdis(o,b)-r);
    Point n=Point( (o.x+cn*b.x)/(1+cn) , (o.y+cn*b.y)/(1+cn) );
    double ret1 = acos( m*n/m.sqrx()/n.sqrx() )*r*r;
    double ret2 = acos( p1*p2/p1.sqrx()/p2.sqrx() )*r*r-fabs(xmult(p1,p2,o));
    double ret=(ret1-ret2)/2.0;
    if(xmult(a,b,o)<eps && sign>0.0 || xmult(a,b,o)>eps && sign<0.0) ret=-ret;
    return ret;
}

int main()
{
    double k;
    int tt = 0;
    while(~scanf("%d %lf", &n, &k))
    {
        double x, y;
        for(int i = 1; i <= n; i++)
        {
            scanf("%lf %lf", &x, &y);
            p[i] = Point(x, y);
        }
        scanf("%lf %lf", &x, &y);
        A = Point(x, y);
        scanf("%lf %lf", &x, &y);
        B = Point(x, y);
        double D = (2*k*k*A.x - 2*B.x) / (1 - k*k);
        double E = (2*k*k*A.y - 2*B.y) / (1 - k*k);
        double F = (B.x*B.x + B.y*B.y - k*k*A.x*A.x - k*k*A.y*A.y) / (1 - k*k);
        C = Circle(Point(-D/2, -E/2), sqrt(D*D/4 + E*E/4 - F) );
        double ans = 0.0;
        p[n+1] = p[1];
        for(int i = 1; i <= n; i++)
            ans += Triangle_Circle_Area(p[i], p[i+1], C.c, C.r);
        printf("Case %d: %.10f\n", ++tt, fabs(ans));
    }
    return 0;
}
View Code

 

posted @ 2018-08-21 22:52  舒羽倾  阅读(199)  评论(0编辑  收藏  举报