zoukankan      html  css  js  c++  java
  • 计算几何学习1

    目前在跟着这个题目列表

    来学习, 目前进行了一中的大部分,模板是参考唐天晓学长的板子和白书来搞的。

    学习的内容:

    1.复数类的一些常用操作

    typedef complex <double> Point;// 复数类来简化代码
    Point a;
    a.real(), a.imag();// a的实部与虚部 对应二维平面 x,y 
    abs(a);// 向量a的模/a到原点距离 
    norm(a);// 模的平方 
    arg(a);// a对应的角度 (弧度制 
    conj(a);// a的共轭 (来计算点积与叉积
    polar(r, theta);// 返回极坐标 (r, theta) 的 Point型 
    View Code

    2.关于点/向量的一些操作

    double Det(const Point & a, const Point & b){//叉积 
        return (conj(a) * b).imag();
    }
    
    double Dot(const Point & a, const Point & b){//点积 
        return (conj(a) * b).real();
    }
    
    int sgn(double x) {//浮点数的正负比较 
        if(abs(x) < eps) return 0;
        if(x < 0) return -1;
        return 1;
    }
    
    Point Rotate(const Point & o , double theta){//仿射变换 将一个点绕原点 逆时针旋转theta 
        return (Point) {o.real() * cos(theta) - o.imag() * sin (theta), o.real() * sin(theta) + o.imag() * cos(theta)};
    }
    
    Point ConvertPoint(const Point & u ,const Point & v, const Point & o){//坐标变换 
        // A * u + B * v = o 不成立的情况下 
        //求o在 u ,v 为基底的情况下的坐标 
        return (Point) {Det(o, v) / Det(u, v), Det(o, u) / Det(v, u)};
    }
    View Code

    3.关于线的一些操作

    struct Line : public vector <Point>{//存储直线上的两点 或表示线段 
        Line(){};
        Line(const Point & a, const Point & b){
            push_back(a);
            push_back(b);
            return;
        }
    };
    
    Point Vec(const Point & a){//单位向量 
        return a / abs(a);
    }
    
    Point Vec(const Line & a) {//方向向量 
        return a[1] - a[0];
    }
    
    Point LineIntersection(const Line & a, const Line & b){//直线的交 
        Point u = a[0] - b[0];
        double k1 = Det(Vec(a), Vec(b));
        double k2 = Det(Vec(b), u);
        if(!sgn(k1))//当方向向量共线时 返回 a的端点 外面判断是否平行 
            return a[0];
        return a[0] + Vec(a) * k2 / k1;
    }
    
    bool SegmentIntersection(const Line & a, const Line & b){ //两条线段是否存在交点 
        if(max(a[0].real(), a[1].real()) < min(b[0].real(), b[1].real())) return 0; 
        if(max(b[0].real(), b[1].real()) < min(a[0].real(), a[1].real())) return 0;
        if(max(a[0].imag(), a[1].imag()) < min(b[0].imag(), b[1].imag())) return 0;
        if(max(b[0].imag(), b[1].imag()) < min(a[0].imag(), a[1].imag())) return 0;
        Point t1 = Vec(a), t2 = Vec(b);
        return (sgn(Det(a[0] - b[0], t2)) * sgn(Det(a[1] - b[0], t2)) <= 0) && (sgn(Det(b[0] - a[0], t1)) * sgn(Det(b[1] - a[0], t1)) <= 0); 
    }
    
    int LSFLAG = 0;//用于判断交点是否存在 是否在线段上 
    Point LSIntersection(const Line & a, const Line & b){//线段与直线的交 a为线段 b为直线 
        Point c = LineIntersection (a, b);
        LSFLAG = 0;
        if(sgn(Det(a[0] - b[0], Vec(b))) * sgn(Det(a[1] - b[0], Vec(b))) > 0 ){
            LSFLAG = -1;
            return c;
        }
        if(!sgn(Det(Vec(a), Vec(b)))) LSFLAG = -1;//平行 或  重合 交点无意义 
        else{
            if(sgn(Dot(a[0] - c, a[1] - c)) <= 0) return c;//交点在线段上 
            else LSFLAG = -1;//交点不在线段上 
        }
        return c;
    }
    
    Point CrossVP(const Line & v, const Point & u){//找点到直线距离(最近点 返回垂足 
        if(!sgn(v[0].real() - v[1].real()) && !sgn(v[0].imag() - v[1].imag())) return v[0];
        if(sgn(Dot(Vec(v), u - v[0])) < 0) return v[0];//删掉两行是直线 一行不删是线段 
        if(sgn(Dot(Vec(v), u - v[1])) > 0) return v[1];//删掉这行是射线
        double a = Dot(Vec(v), u - v[0]);
        return v[0] + a / norm(Vec(v)) * Vec(v);
    }
    View Code

    一些题目和注意事项:

    模板题:

    poj 1269 直线交

    poj 2653 线段交

    poj 2624 裸向量  *注意题目中输入时点的顺序可能不确定

    poj 1569 判断点是否在在凸多边形内部 凸多边形面积求法 *注意在边界的情况有一部分叉积为0 *多边形叉积出来面积有向 比较大小时abs

    不是很模板的题:

    poj 3304

    转化问题:是否存在一条直线与所有给定线段相交

    假如存在一条这样直线 我们一定可以通过平移或旋转一定角度 来使这条直线恰好通过 某些线段的两个端点

    因此枚举端点 + 直线与线段的交

    *枚举不同端点时 注意判断重复的点

    poj 1039

    光线由一头通过一条无反射,无折射的管道中最多能传播多远(最远x坐标

    跟上面的问题类似

    一条可行直线可以通过平移 旋转使其贴到上下边界各一个端点

    而通过的部分一定会和端点处垂直的线段相交(不规范相交 端点处可以通过)

    因此

    1)枚举上下端点来确定直线, 判断是否能与起始的垂直线段相交(首先要从起始线段射出光线

    2)如果能通过所有拐角处垂直线段 一定会通过整条管道

    3) 在做不到2)的情况下 找到最靠前的无法相交的垂线段 之前的上下边界处可更新答案

    *注意计算几何题目中给出的数据范围 这道题点的坐标没有给范围 起始可能为负

    poj 1556

    线段交 + 最短路

    *RE的可能情况

    1)除0

    2)数组越界 下标计算出了问题 或者 数组本身不够大

    3)  死循环

    明天的目标:

    考虑到训练赛和可能的补题,尽量完成提到的blog中的第一部分的剩余内容

    以及kuangbin的练习题的剩余部分

    尽量在周三开始凸包及之后内容的学习

  • 相关阅读:
    递归函数及Java范例
    笔记本的硬盘坏了
    “References to generic type List should be parameterized”
    配置管理软件(configuration management software)介绍
    WinCE文件目录定制及内存调整
    使用Silverlight for Embedded开发绚丽的界面(3)
    wince国际化语言支持
    Eclipse IDE for Java EE Developers 与Eclipse Classic 区别
    WinCE Heartbeat Message的实现
    使用Silverlight for Embedded开发绚丽的界面(2)
  • 原文地址:https://www.cnblogs.com/drzdk/p/7197226.html
Copyright © 2011-2022 走看看