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开发环境配置
    1.java的基础和数据类型
    0、原生jdbc工厂类
    spring中使用quartz动态添加定时任务执行sql
    app前端代码打包步骤
    less的解析笔记
    转:玩转HTML5移动页面(动效篇)
    HTML5属性备忘单
    玩转git和github
    js基础----数组
  • 原文地址:https://www.cnblogs.com/drzdk/p/7197226.html
Copyright © 2011-2022 走看看