计算几何常用函数
结构体与向量
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 struct Point { double x, y; Point(double x = 0, double y = 0) : x(x), y(y) {} }; typedef Point Vector; Vector operator+ (Vector A, Vector B) { return Vector(A.x+B.x, A.y+B.y); } Vector operator- (Vector A, Vector B) { return Vector(A.x-B.x, A.y-B.y); } Vector operator* (Vector A, double p) { return Vector(A.x*p, A.y*p); } Vector operator/ (Vector A, double p) { return Vector(A.x/p, A.y/p); } bool operator< (const Point &a, const Point &b) { return a.x < b.x || (a.x == b.x && a.y < b.y); } const double eps = 1e-8; int dcmp(double x) { if (fabs(x) < eps) return 0; else return x < 0 ? -1 : 1; } bool operator== (const Point &a, const Point &b) { return dcmp(a.x-b.x) == 0 && dcmp(a.y-b.y) == 0; }
向量运算:点积
1 2 3 4 5 6 7 8 9 double Dot(Vector A, Vector B) { return A.x*B.x + A.y*B.y; } double Length(Vector A) { return sqrt(Dot(A, A)); } double Angle(Vector A, Vector B) { return acos(Dot(A, B) / Length(A) / Length(B)); }
其中角度计算是根据余弦定理,设 a ⃗ , b ⃗ \displaystyle\vec{a}, \displaystyle\vec{b} a , b 的夹角为 θ \theta θ
cos θ = a ⃗ ⋅ b ⃗ ∣ a ⃗ ∣ ⋅ ∣ b ⃗ ∣ \cos{\theta} = \frac{\vec{a} \cdot \vec{b}}{|\vec{a}|\cdot |\vec{b}|}
cos θ = ∣ a ∣ ⋅ ∣ b ∣ a ⋅ b
向量运算:叉积
A × B \bm{A} \times \bm{B} A × B 的几何意义,是向量 A , B \bm{A}, \bm{B} A , B 围成的平行四边形的有向面积
Cross ( v , w ) \text{Cross}(\bm{v}, \bm{w}) Cross ( v , w ) ,正方向 定义为从 v \bm{v} v 向 w \bm{w} w 旋转
1 2 3 4 5 6 double Cross(Vector A, Vector B) { return A.x*B.y - A.y*B.x; } double Area2(Point A, Point B, Point C) { return Cross(B-A, C-A); }
极角,极角排序
根据 STL 函数求极角,对于向量 A i ( x , y ) \bm{A}_i(x, y) A i ( x , y ) ,极角为 atan2 ( y , x ) \text{atan2}(y, x) atan2 ( y , x ) ,单位为弧度
逆时针为正方向,值域为 [ − π , + π ] [-\pi, +\pi] [ − π , + π ] ,保存在数组 ang [ i ] \text{ang}[i] ang [ i ] 中
特别地,很多问题需要对极角排序,然后用双指针计算向量 A i , A j \bm{A}_i, \bm{A}_j A i , A j 的夹角 θ \theta θ
由于极角往往是环形的 ,处理完 A ( i → j ) \bm{A}(i \to j) A ( i → j ) 的夹角,往往还需要处理 A ( j → i ) \bm{A}(j \to i) A ( j → i ) 的夹角
比如 i = n , j = 1 i = n, j = 1 i = n , j = 1 ,求第 n n n 个向量往第 1 1 1 个向量的转角
这里采用拆换成链并复制的方法 ,令 ang [ 1 ⋯ n ] \text{ang}[1\cdots n] ang [ 1 ⋯ n ] 每个元素加上 2 π 2\pi 2 π 之后
放入 ang [ n + 1 ⋯ n + n ] \text{ang}[n+1 \cdots n+n] ang [ n + 1 ⋯ n + n ] 中
此外还可以根据叉积来对极角排序
Cross ( A , B ) = 0 \text{Cross}(A, B) = 0 Cross ( A , B ) = 0 向量重合,Cross ( A , B ) > 0 \text{Cross}(A, B) > 0 Cross ( A , B ) > 0 向量 B B B 在 A A A 上方
Cross ( A , B ) < 0 \text{Cross}(A, B) < 0 Cross ( A , B ) < 0 向量 B B B 在 A A A 下方1 2 3 4 5 6 7 8 double compare(Point A, Point B, Point C) { return Cross(B-A, C-A); } bool cmp(Point A, Point B) { Point O; if (compare(O, A, B) == 0) return A.x < B.x; else return compare(O, A, B) > 0; }
一般情况下,使用 atan2 ( y , x ) \text{atan2}(y, x) atan2 ( y , x ) 库更快,其中 y = Vector . y , x = Vector . x y = \text{Vector}.y, \ x = \text{Vector}.x y = Vector . y , x = Vector . x
向量旋转
向量旋转的公式为 (转角为 α \alpha α )
{ x ′ = x cos α − y sin α y ′ = x sin α + y cos α \begin{cases}
x' = x \cos \alpha - y \sin \alpha \\
y' = x \sin \alpha + y \cos \alpha
\end{cases}
{ x ′ = x cos α − y sin α y ′ = x sin α + y cos α
1 2 3 Vector Rotate(Vector A, double rad) { return Vector(A.x*cos(rad)-A.y*sin(rad), A.x*sin(rad)+A.y*cos(rad)); }
特殊情况,如果令 rad = π 2 \text{rad} = \displaystyle\frac{\pi}{2} rad = 2 π ,并且 A A A 不是 0 \bm{0} 0 向量
可以求出法线,并且将长度归一化
1 2 3 4 Vector Normal(Vector A) { double L = Length(A); return Vector(-A.y/L, A.x/L); }
点和直线的位置关系
直线的参数方程
直线上的点满足 P = P 0 + t v P = P_0 + t\bm{v} P = P 0 + t v ,已知直线上两个点 A , B A, B A , B ,那么
直线表示为 A + ( B − A ) t A+ (B-A) \bm{t} A + ( B − A ) t
直线的交点
两条直线分别为 P + t 1 v P+ t_1 \bm{v} P + t 1 v ,Q + t 2 w Q+ t_2 \bm{w} Q + t 2 w ,令 u = P − Q \bm{u} = P-Q u = P − Q
{ u x = − v x t 1 + w x t 2 u y = − v y t 1 + w y t 2 ⇒ \begin{cases}
u_x = -v_xt_1 + w_xt_2 \\
u_y = -v_yt_1 + w_yt_2
\end{cases}
\Rightarrow
{ u x = − v x t 1 + w x t 2 u y = − v y t 1 + w y t 2 ⇒
( − v x w x − v y w y ) ( t 1 t 2 ) = ( u x u y ) \begin{pmatrix}
-v_x & w_x \\
-v_y & w_y
\end{pmatrix}
\begin{pmatrix}
t_1 \\
t_2
\end{pmatrix} =
\begin{pmatrix}
u_x \\
u_y
\end{pmatrix}
( − v x − v y w x w y ) ( t 1 t 2 ) = ( u x u y )
伴随矩阵定义为矩阵 A \bm{A} A 的余子式矩阵的转置
K = det ∣ − v x w x − v y w y ∣ ⇒ ( t 1 t 2 ) = ( w y − w x v y − v x ) K ⋅ ( u x u y ) K = \det \left| \begin{matrix}
-v_x & w_x \\
-v_y & w_y
\end{matrix}\right|
\Rightarrow
\begin{pmatrix}
t_1 \\
t_2
\end{pmatrix} = \frac{\begin{pmatrix}
w_y & -w_x \\
v_y & -v_x
\end{pmatrix}}{K}
\cdot
\begin{pmatrix}
u_x \\
u_y
\end{pmatrix}
K = det ∣ ∣ ∣ ∣ ∣ − v x − v y w x w y ∣ ∣ ∣ ∣ ∣ ⇒ ( t 1 t 2 ) = K ( w y v y − w x − v x ) ⋅ ( u x u y )
由此可以推出
( t 1 t 2 ) = ( u x w y − u y w x u x v y − u y v x ) w × v \begin{pmatrix}
t_1 \\
t_2
\end{pmatrix} =
\frac{\begin{pmatrix}
u_xw_y - u_yw_x \\
u_xv_y - u_yv_x
\end{pmatrix}}{\bm{w} \times \bm{v}}
( t 1 t 2 ) = w × v ( u x w y − u y w x u x v y − u y v x )
令 u = Q P → \bm{u} = \overrightarrow{QP} u = Q P ,直线分别为 P + t v P+t\bm{v} P + t v ,Q + t w Q+t\bm{w} Q + t w
向量 u \bm{u} u 从第二条直线指向第一条直线
两直线交点在第一条直线上的参数为 t 1 t_1 t 1 ,在第二条直线上的参数为 t 2 t_2 t 2
t 1 = cross ( w , u ) cross ( v , w ) , t 2 = cross ( v , u ) cross ( v , w ) t_1 = \frac{\text{cross}(\bm{w}, \bm{u})}{\text{cross}(\bm{v}, \bm{w})}, \quad
t_2 = \frac{\text{cross}(\bm{v}, \bm{u})}{\text{cross}(\bm{v}, \bm{w})}
t 1 = cross ( v , w ) cross ( w , u ) , t 2 = cross ( v , w ) cross ( v , u )
1 2 3 4 5 Point lineIntersection(Point P, Vector v, Point Q, Vector w) { Vector u = P-Q; double t = Cross(w, u) / Cross(v, w); return P + v*t; }
点到直线的距离
可以利用多边形面积公式,对于直线 A B AB A B ,直线外的点为 P P P
先计算三角形 P A B PAB P A B 的有向面积的 2 2 2 倍,S = cross ( A B → , A P → ) S = \text{cross}(\overrightarrow{AB}, \overrightarrow{AP}) S = cross ( A B , A P )
P P P 到 A B AB A B 的距离为三角形的高,D = cross ( A B → , A P → ) / Length ( A B → ) D = \text{cross}(\overrightarrow{AB}, \overrightarrow{AP}) / \text{Length}(\overrightarrow{AB}) D = cross ( A B , A P ) / Length ( A B )
1 2 3 4 double distToLine(Point P, Point A, Point B) { Vector v1 = B-A, v2 = P-A; return fabs(Cross(v1, v2) / Length(v1)); }
点到线段的距离
不妨设 P P P 在线段 A B AB A B 上的投影点为 Q Q Q ,如果
⟨ A B → , A P → ⟩ < 0 \langle \overrightarrow{AB}, \overrightarrow{AP} \rangle< 0 ⟨ A B , A P ⟩ < 0 ,Q Q Q 在 A B AB A B 左侧,此时长度为 ∣ A P → ∣ |\overrightarrow{AP}| ∣ A P ∣
⟨ A B → , B P → ⟩ > 0 \langle \overrightarrow{AB}, \overrightarrow{BP} \rangle> 0 ⟨ A B , B P ⟩ > 0 ,Q Q Q 在 A B AB A B 右侧,此时长度为 ∣ B P → ∣ |\overrightarrow{BP}| ∣ B P ∣
其他情况,只要求出点到直线的距离即可
1 2 3 4 5 6 7 double distToSegment(Point P, Point A, Point B) { if (A == B) return Length(P-A); Vector v1 = B-A, v2 = P-A, v3 = P-B; if (dcmp(Dot(v1, v2)) < 0) return Length(v2); else if (dcmp(Dot(v1, v3)) > 0) return Length(v3); else return fabs( Cross(v1, v2) / Length(v1) ); }
点在直线上的投影
直线为 A B → = v \overrightarrow{AB} = \bm{v} A B = v ,参数方程为 A + t v A+t\bm{v} A + t v
假设投影点为 Q Q Q ,Q Q Q 对应的参数为 t 0 t_0 t 0 ,那么 Q → = A + t 0 v \overrightarrow{Q}=A+t_0\bm{v} Q = A + t 0 v
从而有 Q P → = P − ( A + t 0 v ) \overrightarrow{QP} = P-(A+t_0\bm{v}) Q P = P − ( A + t 0 v )
⟨ v , P − ( A + t 0 v ) ⟩ = 0 \langle \bm{v}, P-(A+t_0 \bm{v}) \rangle = 0 ⟨ v , P − ( A + t 0 v ) ⟩ = 0 ,即 ⟨ v , P − A ⟩ − t 0 ⟨ v , v ⟩ = 0 \langle \bm{v}, P-A \rangle - t_0 \langle \bm{v}, \bm{v} \rangle = 0 ⟨ v , P − A ⟩ − t 0 ⟨ v , v ⟩ = 0
计算出 t 0 = Dot ( v , P − A ) Dot ( v , v ) t_0 = \displaystyle \frac{\text{Dot}(\bm{v}, P-A)}{\text{Dot}(\bm{v}, \bm{v})} t 0 = Dot ( v , v ) Dot ( v , P − A ) ,从而 A + v ⋅ t 0 A + \bm{v} \cdot t_0 A + v ⋅ t 0 就是 Q Q Q
1 2 3 4 Point getLineProjection(Point P, Point A, Point B) { Vector v = B-A; return A + v * (Dot(v, P-A) / Dot(v, v)); }
线段树维护矩阵变换
Gentle Jena II
x , y x, y x , y 绕原点逆时针旋转,可以通过矩阵变换描述
( cos t − sin t sin t cos t ) ( x y ) \begin{pmatrix}
\cos t & -\sin t \\
\sin t & \cos t
\end{pmatrix}
\begin{pmatrix}
x \\
y
\end{pmatrix}
( cos t sin t − sin t cos t ) ( x y )
如果绕特定的点 ( X , Y ) (X, Y) ( X , Y ) 旋转角度 t t t ,可以写成
先平移 ( − a , − b ) (-a, -b) ( − a , − b ) ,再绕原点旋转,最后再平移 ( a , b ) (a, b) ( a , b ) ,构造仿射变换如下
( 1 0 X 0 1 Y 0 0 1 ) ( cos t − sin t 0 sin t cos t 0 0 0 1 ) ( 1 0 − X 0 1 − Y 0 0 1 ) ( x y 1 ) \begin{pmatrix}
1 & 0 & X \\
0 & 1 & Y \\
0 & 0 & 1
\end{pmatrix}
\begin{pmatrix}
\cos t & - \sin t & 0 \\
\sin t & \cos t & 0 \\
0 & 0 & 1
\end{pmatrix}
\begin{pmatrix}
1 & 0 & -X \\
0 & 1 & -Y \\
0 & 0 & 1
\end{pmatrix}
\begin{pmatrix}
x \\
y \\
1
\end{pmatrix}
⎝ ⎛ 1 0 0 0 1 0 X Y 1 ⎠ ⎞ ⎝ ⎛ cos t sin t 0 − sin t cos t 0 0 0 1 ⎠ ⎞ ⎝ ⎛ 1 0 0 0 1 0 − X − Y 1 ⎠ ⎞ ⎝ ⎛ x y 1 ⎠ ⎞
另外注意矩阵变换是满足分配律的,比如对于当前星星 A i = ( x i y i ) \bm{A}_i = \displaystyle \binom{x_i}{y_i} A i = ( y i x i ) ,对于变换 P \bm{P} P
P ( A 1 + A 2 + ⋯ A n ) = P A 1 + P A 2 + ⋯ P A n = A 1 ′ + A 2 ′ + ⋯ A n ′ \bm{P}(\bm{A}_1 + \bm{A}_2 + \cdots \bm{A}_n) = \bm{PA}_1 + \bm{PA}_2 + \cdots \bm{PA}_n = \bm{A}'_1 + \bm{A}'_2 + \cdots \bm{A}'_n P ( A 1 + A 2 + ⋯ A n ) = P A 1 + P A 2 + ⋯ P A n = A 1 ′ + A 2 ′ + ⋯ A n ′
所以只需要用线段树维护 s x = ∑ x , s y = ∑ y sx = \sum x, \ sy = \sum y s x = ∑ x , s y = ∑ y ,分别表示区间中所有星星 x , y x, y x , y 坐标的和
构造仿射变换 P \bm{P} P
初始化,对于每一个星星 i i i ,s x = x i , s y = y i sx = x_i, sy = y_i s x = x i , s y = y i ,建立线段树
对于操作 1 1 1 ,即执行仿射变换 P \bm{P} P ,只需要 P ⋅ ( s x , s y ) T \bm{P}\cdot (sx, sy)^{T} P ⋅ ( s x , s y ) T ,难点在于 push \text{push} push 和 pull \text{pull} pull 怎么写,以及懒标记处理
( s x ′ , s y ′ ) T ← P ⋅ ( s x , s y ) T (sx', sy')^{T} \leftarrow \bm{P}\cdot (sx, sy)^{T} ( s x ′ , s y ′ ) T ← P ⋅ ( s x , s y ) T
每次修改,难点在于 lazy \text{lazy} lazy 如何处理
lazy \textbf{lazy} lazy 初始化为单位矩阵 I \bm{I} I ,每一次对线段树节点 p p p 执行变换 C \bm{C} C 时
C ⋅ ( t p . s x , t p . s y ) T \bm{C} \cdot (t_p.sx, t_p.sy)^{T} C ⋅ ( t p . s x , t p . s y ) T 执行矩阵乘法,并且下传延迟标记
递归到的每一个子区间都被修改了,后面的修改是基于前面修改基础上的
对于子区间,执行 t ( p ≪ 1 ) . lazy ← C ⋅ t ( p ≪ 1 ) . lazy t(p \ll 1).\textbf{lazy} \leftarrow \bm{C} \cdot t(p \ll 1).\textbf{lazy} t ( p ≪ 1 ) . lazy ← C ⋅ t ( p ≪ 1 ) . lazy ,右子树同理
pull \text{pull} pull 操作只需要执行,t ( p ) . s x = t ( p ≪ 1 ) . s x + t ( p ≪ 1 ∣ 1 ) . s x t(p).sx = t(p \ll 1).sx + t(p\ll 1 \mid 1).sx t ( p ) . s x = t ( p ≪ 1 ) . s x + t ( p ≪ 1 ∣ 1 ) . s x
对于操作 2 2 2 的问询,只需要注意每次递归查询时候,下传延迟标记,最后找到表示区间 [ l i , r i ] [li, ri] [ l i , r i ] 的节点 u u u
t ( u ) . s x , t ( u ) . s y t(u).sx, t(u).sy t ( u ) . s x , t ( u ) . s y 就是答案,注意在修改操作中更新 s x , s y sx, sy s x , s y 需要取 mod \text{mod} mod
坑点提示
∑ ( P A i ) = P ( ∑ A i ) \sum \left(\bm{PA}_i \right) = \bm{P} \left(\sum \bm{A}_i \right)
∑ ( P A i ) = P ( ∑ A i )
所以维护的矩阵变换应该是
P ⋅ ( s x s y len ( p ) ) \bm{P} \cdot
\begin{pmatrix}
sx \\
sy \\
\text{len}(p)
\end{pmatrix}
P ⋅ ⎝ ⎛ s x s y len ( p ) ⎠ ⎞
其中 len ( p ) \text{len}(p) len ( p ) 表示线段树 p p p 节点的区间长度
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 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 const int maxn = 1e5 + 500; const int mod = 998244353; int n, m; typedef vector<vector<ll> > Matrix; Matrix I(3, vector<ll>(3, 0)); void init () { for (int i = 0; i < 3; i++) I[i][i] = 1; } struct Point { int x, y; } a[maxn]; Matrix trans(const Matrix &A, const Matrix &B) { int _n = A.size(), _m = B[0].size(); Matrix res(_n, vector<ll> (_m, 0)); for (int i = 0; i < _n; i++) { for (int j = 0; j < _m; j++) for (int k = 0; k < (int)A[0].size(); k++) res[i][j] = res[i][j] + A[i][k] * B[k][j]; } return res; } Matrix mul(const Matrix &A, const Matrix &B) { int _n = A.size(), _m = B[0].size(); Matrix res(_n, vector<ll> (_m, 0)); for (int i = 0; i < _n; i++) { for (int j = 0; j < _m; j++) for (int k = 0; k < (int)A[0].size(); k++) res[i][j] = (res[i][j] + A[i][k] * B[k][j] + mod) % mod; } return res; } Matrix get_matrix(int X, int Y) { Matrix A(3, vector<ll>(3, 0)); for (int i = 0; i < 3; i++) A[i][i] = 1; A[0][2] = X, A[1][2] = Y; Matrix B(3, vector<ll>(3, 0)); B[0][1] = -1, B[1][0] = 1, B[2][2] = 1; Matrix C(3, vector<ll>(3, 0)); for (int i = 0; i < 3; i++) C[i][i] = 1; C[0][2] = -X, C[1][2] = -Y; Matrix res = A; res = trans(res, B); res = trans(res, C); return res; } namespace segTree { struct node { int l, r, tag; ll sx, sy; Matrix lazy; } t[maxn << 2]; void pull(int p) { t[p].sx = (t[p<<1].sx + t[p<<1|1].sx + mod) % mod; t[p].sy = (t[p<<1].sy + t[p<<1|1].sy + mod) % mod; } void apply(int p, const Matrix& C) { Matrix cur(3, vector<ll>(1, 0)); cur[0][0] = t[p].sx, cur[1][0] = t[p].sy, cur[2 ][0] = t[p].r-t[p].l+1; Matrix nxt = trans(C, cur); t[p].sx = nxt[0][0], t[p].sy = nxt[1][0]; } void push(int p) { if (!t[p].tag) return ; if (t[p].l == t[p].r) return ; t[p].tag = 0; t[p<<1].tag = t[p<<1 |1].tag = 1; Matrix C = t[p].lazy; t[p<<1].lazy = trans(C, t[p<<1 ].lazy); t[p<<1|1 ].lazy = trans(C, t[p<<1|1 ].lazy); t[p].lazy = I; apply(p<<1, C), apply(p<<1 |1, C); } void build(int p, int l, int r) { t[p].l = l, t[p].r = r; t[p].lazy = I; if (l >= r) { t[p].sx = a[l].x, t[p].sy = a[l].y; return ; } int mid = (l+r) >> 1; build(p<<1, l, mid); build(p<<1 |1, mid+1, r); pull(p); } void change(int p, const int l, const int r, const Matrix &P) { if (l <= t[p].l && t[p].r <= r) { t[p].tag = 1; apply(p, P); t[p].lazy = trans(P, t[p].lazy); return ; } push(p); t[p].sx = t[p].sy = 0; int mid = (t[p].l + t[p].r) >> 1; if (l <= mid) change(p<<1, l, r, P); if (r > mid) change(p<<1 |1, l, r, P); pull(p); } ll query(int p, const int l, const int r, bool fl) { if (l <= t[p].l && t[p].r <= r) { if (fl == 0) return (t[p].sx + mod) % mod; else return (t[p].sy + mod) % mod; } if (fl == 0) push(p); ll ans = 0; int mid = (t[p].l + t[p].r) >> 1; if (l <= mid) ans = (ans + query(p<<1, l, r, fl) + mod) % mod; if (r > mid) ans = (ans + query(p<<1 |1, l, r, fl) + mod) % mod; return ans; } } int main () { //freopen("input.txt" , "r" , stdin); cin >> n >> m; init(); using namespace segTree; // get data for (int i = 1; i <= n; i++) scanf("%d%d" , &a[i].x, &a[i].y); build(1, 1, n); // get change while (m--) { int op, li, ri; scanf("%d%d%d" , &op, &li, &ri); //debug(op), debug(li), debug(ri); if (op == 1) { int X, Y; scanf("%d%d" , &X, &Y); Matrix P = get_matrix(X, Y); //dbg(P); change(1, li, ri, P); } if (op == 2) { ll sumx = query(1, li, ri, 0); ll sumy = query(1, li, ri, 1); //debug(sumy); sumx = (sumx + mod) % mod, sumy = (sumy + mod) % mod; ll ans = (sumx * sumy + mod) % mod; printf ("%lld\n" , ans); } } }
行列式计算
直接从定义出发,递归计算
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 typedef vector<vector<double> > Matrix; double calc(Matrix det) { int n = det.size(); if (n == 1) return det[0][0]; double detval = 0; Matrix tmp = vector<vector<double> >(n-1, vector<double> (n-1, 0)); for (int i = 0; i < n; i++) { for (int j = 0; j < n-1; j++) for (int k = 0; k < n-1; k++) { if (k < i) tmp[j][k] = det[j+1][k]; else tmp[j][k] = det[j+1][k+1]; } detval += det[0][i] * pow(-1.0, i) * calc(tmp); } return detval; }