Chgtaxihe's blog Chgtaxihe's blog
首页
练习
算法学习
读书笔记
小玩意

Chgtaxihe

首页
练习
算法学习
读书笔记
小玩意
  • 数论

  • 动态规划

  • 暴力

  • 图论

  • 数据结构

  • 字符串

  • 几何

    • 几何模板
      • 点/向量定义
      • 两线段相交
      • 三角形外心
      • 坐标系旋转
    • 凸包学习笔记
    • 多边形面积
    • 皮克定理
  • 博弈论

  • 其他

几何模板

# 几何模板

# 点/向量定义

struct vec{ // 向量
    T x, y;
    vec(){}
    vec(T dx, T dy){x = dx, y = dy;}
    vec(vec from, vec to){x = to.x - from.x, y = to.y - from.y;}
    vec operator +(const vec oth)const {return {x + oth.x, y + oth.y};}
    vec operator -(const vec oth)const {return {x - oth.x, y - oth.y};}
    vec operator *(double times)const {return {x * times, y * times};}
    T operator *(const vec oth){return x*oth.y - y*oth.x;} // 外积(叉积)
    T operator ^(const vec oth){return x*oth.x + y*oth.y;} // 内积(点积)
    T len()const {return std::sqrt(x * x + y * y);}
    bool operator <(const vec & oth)const{
        if(y == oth.y) return x < oth.x;
        return y < oth.y;
    }
};
typedef vec point; // 点
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 两线段相交

# 三角形外心

由于涉及到平方的计算,因此要考虑使用double或__int128_t

static pair<double, double> circumcentre_pr(point p0, point p1, point p2){ // 求三角形外心
    T a = 2 * (p1.x - p0.x), b = 2 * (p1.y - p0.y);
    T c = 2 * (p2.x - p0.x), d = 2 * (p2.y - p0.y);
    T b1 = p1.x * p1.x - p0.x * p0.x + p1.y * p1.y - p0.y * p0.y;
    T b2 = p2.x * p2.x - p0.x * p0.x + p2.y * p2.y - p0.y * p0.y;
    double dem = a * d - b * c;
    T d1 = b1 * d - b2 * b, d2 = a * b2 - c * b1;
    return {1.0 * d1 / dem, 1.0 * d2 / dem};
}

static point circumcentre(point p0, point p1, point p2){ // 求三角形外心
    pair<double, double> ans = circumcentre_pr(p0, p1, p2);
    return point((T)ans.first, (T)ans.second);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

当然,还有另一种计算方法,其优势在于可以预处理部分参数,避免重复计算

# 坐标系旋转

在将坐标系逆时针旋转θ\thetaθ角后,原坐标与新坐标的关系如下

(x′y′)=(cos⁡θ−sin⁡θsin⁡θcos⁡θ)(xy)x′=xcos⁡θ+ysin⁡θy′=ycos⁡θ−xsin⁡θ\left(\begin{array}{l}x^{\prime} \\y^{\prime}\end{array}\right)=\left(\begin{array}{cc}\cos \theta & -\sin \theta \\\sin \theta & \cos \theta\end{array}\right)\left(\begin{array}{l}x \\y\end{array}\right)\\\begin{aligned}x'&=x\cos\theta+y\sin\theta\\y'&=y\cos\theta-x\sin\theta\end{aligned} (x′y′​)=(cosθsinθ​−sinθcosθ​)(xy​)x′y′​=xcosθ+ysinθ=ycosθ−xsinθ​

# (不)完整代码

写到心力憔悴,晚点再来完善

PS: POJ上就别用这套模板了,得该成C98的风格(心累)

template<class T>
struct geometry{

    const constexpr static double eps = 1e-8;

    struct vec{ // 向量
        T x, y;
        vec(){}
        vec(T dx, T dy){x = dx, y = dy;}
        vec(vec from, vec to){x = to.x - from.x, y = to.y - from.y;}
        vec operator +(const vec oth)const {return {x + oth.x, y + oth.y};}
        vec operator -(const vec oth)const {return {x - oth.x, y - oth.y};}
        vec operator *(double times)const {return {x * times, y * times};}
        T operator *(const vec oth){return x*oth.y - y*oth.x;} // 外积(叉积)
        T operator ^(const vec oth){return x*oth.x + y*oth.y;} // 内积(点积)
        T len()const {return (T)std::sqrt(x * x + y * y);}
        bool operator <(const vec & oth)const{
            if(y == oth.y) return x < oth.x;
            return y < oth.y;
        }
    };
    typedef vec point; // 点
    struct edge{ // 线段
        point a, b;
    };

    static T sign_test(T val){
        if(val > eps) return 1;
        if(val < -eps) return -1;
        return 0;
    }

    static T dist(point p1, point p2){
        return vec(p1, p2).len();
    }

    static bool on_edge(point p, edge e){ // 判断点是否在线段(含端点)上
        return sign_test((e.a-p)*(e.b-p)) == 0 && sign_test((e.a-p)^(e.b-p)) <= 0;
    }

    static bool is_cross(edge l1, edge l2){ // 规范相交(不存在三点共线)
        T s1 = sign_test((l1.b-l1.a)*(l2.a-l1.a)), s2 = sign_test((l1.b-l1.a)*(l2.b-l1.a));
        T s3 = sign_test((l2.b-l2.a)*(l1.a-l2.a)), s4 = sign_test((l2.b-l2.a)*(l1.b-l2.a));
        if(s1 * s2 < 0 && s3 * s4 < 0) return true;
        return false;
    }

    static point cross_point(edge l1, edge l2){
        double area1 = fabs(vec(l1.a, l2.a) * vec(l1.a, l2.b));
        double area2 = fabs(vec(l1.b, l2.a) * vec(l1.b, l2.b));
        return (l1.a * area1 + l1.b * area2) * (1 / (area1 + area2));
    }

    static double sine(vec v1, vec v2){return (v1 * v2) * 1.0 / (v1.len() * v2.len());}
    static double cosine(vec v1, vec v2){return (v1 ^ v2) * 1.0 / (v1.len() * v2.len());}

    static T triangle_area(vec v1, vec v2){
        T result = (v1 * v2) / 2;
        return result>0?result:-result;
    }

    static pair<double, double> circumcentre_pr(point p0, point p1, point p2){ // 求三角形外心
        T a = 2 * (p1.x - p0.x), b = 2 * (p1.y - p0.y);
        T c = 2 * (p2.x - p0.x), d = 2 * (p2.y - p0.y);
        T b1 = p1.x * p1.x - p0.x * p0.x + p1.y * p1.y - p0.y * p0.y;
        T b2 = p2.x * p2.x - p0.x * p0.x + p2.y * p2.y - p0.y * p0.y;
        double dem = a * d - b * c;
        T d1 = b1 * d - b2 * b, d2 = a * b2 - c * b1;
        return {1.0 * d1 / dem, 1.0 * d2 / dem};
    }

    static point circumcentre(point p0, point p1, point p2){ // 求三角形外心
        pair<double, double> ans = circumcentre_pr(p0, p1, p2);
        return point((T)ans.first, (T)ans.second);
    }

    static void sort_by_angle(vector<point> & pts){
        for(int i=1; i<pts.size(); i++)
            if(pts[i] < pts[0]) swap(pts[i], pts[0]);
        point base = pts[0];
        sort(pts.begin()+1, pts.end(), [&](point x1, point x2){
            vec v1(base, x1), v2(base, x2);
            double k = v1 * v2;
            return k==0?v1.len()<v2.len():k>0; // 按辐角排序,相同则短者优先
        });
    }

    static vector<point> convec_hull(vector<point> & pts){
        sort_by_angle(pts);
        int steck[pts.size()], head=0;
        steck[head++] = 0;
        for(int i=1; i<pts.size(); i++){
            while(head > 1 && vec(pts[steck[head-2]], pts[steck[head-1]])*vec(pts[steck[head-1]], pts[i])<=0) head--;
            steck[head++] = i;
        }
        vector<point> ret(head);
        for(int i=0; i<head; i++) ret[i] = pts[steck[i]];
        return ret;
    }
};

using geo = geometry<double>;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
上次更新: 2021/02/24, 03:37:30
字符串基础
凸包学习笔记

← 字符串基础 凸包学习笔记→

最近更新
01
深入理解Java虚拟机
03-04
02
DNS工作原理
02-27
03
改用VuePress啦
02-23
更多文章>
Theme by Vdoing | Copyright © 2019-2021
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式