计算几何初步(刷蓝书)

Posted revolia-room

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了计算几何初步(刷蓝书)相关的知识,希望对你有一定的参考价值。

 

头文件

技术图片
#include<bits/stdc++.h>
#define max(a,b) (a>b?a:b)
#define min(a,b) (a<b?a:b)
using namespace std;
typedef long long ll;
const int maxn = 1e3+7;
const double esp = 1e-6;
int dcmp(double x)
    if(fabs(x)<esp)return 0;
    return x<0?-1:1;

struct Point
    double x,y;
    void read()scanf("%lf%lf",&x,&y);
    Point(double x = 0,double y = 0):x(x),y(y)
;
double Cross(const Point A,const Point B) return A.x*B.y-A.y*B.x; 
double Dot(const Point A,const Point B) return A.x*B.x+A.y*B.y; 
double Len(const Point A) return sqrt(Dot(A,A)); 
double Angle(const Point A,const Point B) return acos(Dot(A,B)/Len(A)/Len(B)); 
Point operator + (const Point A,const Point B) return Point(A.x+B.x,A.y+B.y); 
Point operator - (const Point A,const Point B) return Point(A.x-B.x,A.y-B.y); 
Point operator * (const Point A,const double B) return Point(A.x*B,A.y*B); 
Point operator / (const Point A,const double B) return Point(A.x/B,A.y/B); 
Point Rotate(const Point A,double rad)return Point(A.x*cos(rad)-A.y*sin(rad),A.x*sin(rad)+A.y*cos(rad));
//负数表示顺时针
Point Normal(const Point A)return Point(-A.y/Len(A),A.x/Len(A));//法向量
bool operator == (const Point A,const Point B)return !dcmp(A.x-B.x)&&!dcmp(A.y-B.y); 
bool operator != (const Point A,const Point B)return !(A == B);
bool operator < (const Point A,const Point B)return A.x<B.x || (A.x == B.x&&A.y<B.y);
typedef Point Vector;
struct Circle
    Point x;
    double r;
    void read()
        x.read();
        scanf("%lf",&r);
    
;
bool quickRepel(Point x1,Point y1,Point x2,Point y2)//快速排斥
    Point Lx = Point(min(x1.x,y1.x),min(x1.y,y1.y));
    Point Rx = Point(max(x1.x,y1.x),max(x1.y,y1.y));

    Point Ly = Point(min(x2.x,y2.x),min(x2.y,y2.y));
    Point Ry = Point(max(x2.x,y2.x),max(x2.y,y2.y));

    Point L = Point(max(Lx.x,Ly.x),max(Lx.y,Ly.y));
    Point R = Point(min(Rx.x,Ry.x),min(Rx.y,Ry.y));

    return (L.x<=R.x) && (L.y<=R.y);

bool OnSegment(Point P,Point x,Point y)//点在线段上
    if(P == x||P == y)return 1;
    return !dcmp(Cross(x-P,y-P))&&dcmp(Dot(P-x,P-y))<0;

bool straddle(Point x1,Point y1,Point x2,Point y2)//跨立实验(线段是否有交点)
    if(!quickRepel(x1,y1,x2,y2))return 0;
    double c1 = Cross(y1-x1,x2-x1),c2 = Cross(y1-x1,y2-x1);
    double c3 = Cross(y2-x2,x1-x2),c4 = Cross(y2-x2,y1-x2);
    return dcmp(c1)*dcmp(c2)<=0 && dcmp(c3)*dcmp(c4)<=0;
    //允许部分重合或在端点重合
    //return dcmp(c1)*dcmp(c2)<0 && dcmp(c3)*dcmp(c4)<0;
    //必须只有一个交点且不在端点上

Point LinearIntersection(Point P,Vector v,Point Q,Vector w)//解直线交点
    assert(v != w);//Parallel 平行线
    Vector u = P-Q;
    double t = Cross(w,u)/Cross(v,w);
    return P+v*t;

Point GetLineProjection(Point P,Point A,Point B)//P投影到AB上的点
    Vector v = B-A;
    return A+v*(Dot(v,P-A)/Dot(v,v));

Point SymmetricPoint(Point P,Point A,Point B)//P关于AB的对称点
    return GetLineProjection(P,A,B)*2.0-P;

double DistanceToline(Point P,Point A,Point B)//点到直线距离
    Vector v1 = B-A,v2 = P-A;
    return fabs(Cross(v1,v2))/Len(v1);

double DistanceToSegment(Point P,Point A,Point B)//点到线段距离
    if(A == B)return Len(P-A);
    Vector v1 = B-A,v2 = P-A,v3 = P-B;
    if(dcmp(Dot(v1,v2))<0)return Len(v2);
    if(dcmp(Dot(v1,v3))>0)return Len(v3);
    return fabs(Cross(v1,v2))/Len(v1);
View Code

 

例题:

Morley‘s Theorem

https://vjudge.net/problem/UVA-11178

注意理解三等分角和三等分边不是一个概念

Point GetPoint(Point A,Point B,Point C)
    Vector v1 = C-B;
    double a1 = Angle(A-B,v1);
    v1 = Rotate(v1,a1/3);

    Vector v2 = B-C;
    double a2 = Angle(A-C,v2);
    v2 = Rotate(v2,-a2/3);
    return LinearIntersection(B,v1,C,v2);

int main()
    int T;
    scanf("%d",&T);
    while(T--)
        Point A,B,C;
        A.read(),B.read(),C.read();
        Point D = GetPoint(A,B,C);
        Point E = GetPoint(B,C,A);
        Point F = GetPoint(C,A,B);
        printf("%.6f %.6f ",D.x,D.y);
        printf("%.6f %.6f ",E.x,E.y);
        printf("%.6f %.6f\n",F.x,F.y);
    
    return 0;

 

好看的一笔画LA3263

= = 我没找着这个题

 

狗的距离

https://vjudge.net/problem/UVA-11796

因为没有加速度,所以可以一条狗为参考系,考虑另一条狗的贡献

每次至少跳一个点,所以复杂度也可以保证最多n+m

模拟即可

Point A[maxn],B[maxn];
double Max,Min;
void update(Point P,Point A,Point B)
    Min = min(Min,DistanceToSegment(P,A,B));
    Max = max(Max,Len(P-A));
    Max = max(Max,Len(P-B));

int main()
    int T,n,m,Case = 0;
    scanf("%d",&T);
    while(T--)
        scanf("%d%d",&n,&m);
        for(int i=0;i<n;i++)A[i].read();
        for(int i=0;i<m;i++)B[i].read();
        double LenA = 0,LenB = 0;
        for(int i=0;i<n-1;i++) LenA += Len(A[i+1]-A[i]);
        for(int i=0;i<m-1;i++) LenB += Len(B[i+1]-B[i]);
        int Sa = 0,Sb = 0;
        Point Pa = A[0],Pb = B[0];
        Min = 1e9,Max = -1e9;
        while(Sa<n-1 && Sb<m-1)
            double La = Len(A[Sa+1]-Pa);
            double Lb = Len(B[Sb+1]-Pb);
            double T = min(La/LenA,Lb/LenB);
            Vector Va = (A[Sa+1]-Pa)/La*T*LenA;
            Vector Vb = (B[Sb+1]-Pb)/Lb*T*LenB;
            update(Pa,Pb,Pb+Vb-Va);
            Pa = Pa+Va;
            Pb = Pb+Vb;
            if(Pa == A[Sa+1])Sa++;
            if(Pb == B[Sb+1])Sb++;
        
        printf("Case %d: %.0f\n",++Case,Max-Min);
    
    return 0;

 

以上是关于计算几何初步(刷蓝书)的主要内容,如果未能解决你的问题,请参考以下文章

HDU6164 计算几何 叉积,点积的初步运用

2/14 计算几何初步

计算几何初步

计算几何初步-三点顺序

计算几何初步-凸包-Jarvis步进法。HDU1392Surround the Trees

计算几何及其应用——计算几何基础