计算几何学习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型 

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)};
}

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);
}

一些题目和注意事项:

模板题:

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的练习题的剩余部分

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

时间: 2024-10-15 22:17:30

计算几何学习1的相关文章

计算几何学习8

由于poj炸了 而题单上有很多poj的题 就先开始第二部分了 学习了两个固定算法 最小圆覆盖和平面上最近点对 平面上最近点对采用的是分治的思想 把一个x有序的序列分成A,B左右两部分 当得到A内最近点对距离,B类最近点对距离后 先更新大序列的答案ans A,B间最近点对的产生 显然在x坐标距离mid点不超过ans的区间内产生 我们把这段区间拿出来,对y排序 再逐对更新 值得注意的地方 1)为了确保速度 可以在第二次对y排序的时候采取对标号排序的方式 2)在枚举点对更新的时候注意在y差值 >= a

计算几何学习6

周末搞完了扫描线的部分 上次说的半平面交问题做法是没问题的 是按照中垂线划分平面 再求核的面积 因为是每加入一个直线就判断 所以n^2的好一点 扫描线板子(poj1177 周长并) #include <cstdio> #include <algorithm> #include <iostream> #include <cstdlib> #include <cstring> #define lc(x) (x << 1) #define

计算几何学习5

今天算是把半平面交的nlogn版本搞出来了 也做了一些半平面交的经典题 最重要的是感受到了 计算几何的精度的深深的恶意 nlogn的做法 和凸包类似 维护一个直线的双端队列 极角排序后每次加入一条直线都从队首队尾弹出无效直线 在加入时和队尾直线产生交点 最后队首队尾产生交点 中间还有当队尾两直线向量共线时的问题需要处理一下 总感觉 n^2的做法虽然慢 但是精度似乎比nlogn的要靠谱 计算几何很多特殊情况的处理让人很蛋疼 poj 3335 模板 试了下 nlogn 和 n ^ 2板子 其他比较简

计算几何学习4

今天完成的内容很少 学习了一点半平面交 n^2的做法还是很平易近人 刚开始初始化一个大有界的平面 依次用每条直线去切割平面即可 原有的点如果在当前直线左侧一定会被保留 而原有多边形的线段 可能会在线段中间出现交点 在判断一下即可 不想加入重复的点 就在交点求出后判断一下 模板题 因为没注意题目的读入顺序可能顺时针可能逆时针 并且多边形也不一定凸 调了很久 其实 n^2的 HPI部分没错的 至于nlogn的照着板子敲了一发 WA了 刘汝佳老师板子很简洁 但是排序很迷 说是直线的极角排序 但没给重载

计算几何学习12 + 组队训练

学习了极角排序的一些套路 UVA11696 给你一些圆和一些点,保证点不在圆内,两点相连通当且仅当两点联结的线段不与任何一个圆相交,问联通块个数 跟之前那道UVA很类似 其实更加简单 枚举每个点 把其他所有点和圆对他极角排序 用set维护圆到当前点的切线的最短距离 因为点不在圆内 所以直接判断距离就行了 poj 2280 给你一些A类点 B类点 寻找一条直线 使得线上的点和直线左侧的A类点 直线右侧的B类点数目之和最大 首先可以知道直线一定从 给定两点的连线中产生 所以考虑枚举点 让其他点对他极

计算几何学习3

完成了题表中的前三部分 (由于二.三部分的内容比较少 一. poj 2826 用两条木板来盛雨水 问能接到多少 线段交 分类讨论 1)只要有一条水平 就不能盛水 2)没有交点 不能盛水 3)有交点 但是交点水平上方 没有分别两个端点不能盛水 4)*有两个端点 但是上侧长的一根覆盖了另一条短的 不能盛水 如果都能满足 就利用交点 算一个三角形面积即可 **学习到最后输出浮点数可以 ans + eps 防止出现 - 0.000的情况 或者需要特判一发 poj 3347 给出一种放置正方形序列的方式(

计算几何学习7

今天搞的都是一些简单的解析几何 有一些东西有固定的求法 求角平分线:先通过角的两边算出角度 再旋转其中一个至角平分线的位置 求垂线:直接通过方向向量求出直线的法向量 三角形的三个心: 外心:两个中垂线交点(三角形外接圆就是外心) 内心:两个角平分线交点 垂心:垂线交点(一个顶点在对边法向量上的直线) 圆的切线:点到圆心的直线 旋转一个角度 可以通过半径和到圆心的距离算 求球面距离:习惯通过球坐标系求出两个点直角坐标系中的方向向量 然后通过点积算出圆心角 再乘上球的半径 今天做的都是这些加上一点变

【笔记篇】最良心的计算几何学习笔记(三)

广告: 先是放一下本文的::github传送门:: (不知道为什么要放) 今天发现了一个AMA(Ask me anything)的东西, 觉得非常好玩, 就fork了一个放到自己的github里面, 估计没有人会来问, 所以就放到这里拉拢人气(虽然这里也拉拢不到) 欢迎大家来玩哦~ 地址请戳这个就是传送门啦~ 今天继续计算几何(明明已经颓废了半下午了 计算多边形面积 我们先从最简单的多边形--三角形开始看. 如何计算\(\triangle ABC\)的面积? 这个问题数学课上老师应该说过.. \

【笔记篇】最良心的计算几何学习笔记(六)

半平面交 github传送门 简介 Emmmm学完旋转卡壳感觉自己已经是个废人了.. 修整了一个周末, 回来接着跟计算几何势力硬干... (这个周末是不是有点长?) 今天就讲讲半平面交吧. 请自己回顾必修五 线性规划相关知识... 什么是半平面? 就是一条直线一侧的点构成的集合.. 用解析几何的观点来看就是满足\(Ax+By+C<0\)这个不等式的点的集合. 那么半平面交自然就是许多这样的集合的交集咯~ 最后就很像线性规划做出来的可行域一样... 半平面交可以长这样 这样 甚至这样 也就是说,