目前在跟着这个题目列表
来学习, 目前进行了一中的大部分,模板是参考唐天晓学长的板子和白书来搞的。
学习的内容:
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的练习题的剩余部分
尽量在周三开始凸包及之后内容的学习