zoukankan      html  css  js  c++  java
  • 线性代数入门

    1. 高斯消元

    模板题

    定义以下三种操作为 初等行变换

    1. 将某一行乘上 (c)
    2. 将某一行的 (c) 倍加到另一行
    3. 交换两行

    这里介绍高斯-约旦消元法,利用初等行变换将矩阵转化成对角矩阵,然后就很容易求出解。

    1. 枚举 (i) 表示现在要消去第 (i)
    2. ([i,n])​ 内选择一个 (k)​ 满足 (a[k][i] eq 0)​,若不存在则说明无解
    3. 交换第 (i) 行和第 (k)
    4. 对于 ([i+1,n])​ 内所有 (j)​,将第 (j)​ 行减去 (dfrac{a[j][i]}{a[i][i]}) 倍的第 (i) 行​

    容易发现,最后第 (i)​ 项系数只会出现在第 (i)​ 行。并且任意时刻,第 (i)​ 行的 (1dots i-1)​ 项系数都为 (0)​​,所以不会对其他方程的这些项造成影响。

    inline bool zero(double t) {
    	return fabs(t) < 1e-8;
    }
    
    signed main() {
    	scanf("%d", &n);
    	rep(i, 1, n) rep(j, 1, n + 1)
    		scanf("%lf", &a[i][j]);
    	rep(i, 1, n) {
    		k = i;
    		if(zero(a[i][i])) rep(j, i + 1, n) if(!zero(a[j][i])) { k = j; break; }
    		if(i ^ k) rep(j, i, n + 1) swap(a[i][j], a[k][j]);
    		if(zero(a[i][i])) return puts("No Solution") & 0;
    		rep(j, 1, n) if(i != j) {
    			t = a[j][i] / a[i][i];
    			rep(k, i, n + 1) a[j][k] -= a[i][k] * t;
    		}
    	}
    	rep(i, 1, n) printf("%.2lf
    ", a[i][n + 1] / a[i][i]);
    	return 0;
    }
    

    2. 行列式

    对于一个方阵,其行列式是线性变换的伸缩因子。例如在三维空间中,行列式表示线性变换造成的体积放大倍率。

    代数定义:(det A=|A|=sumlimits_{p是n的排列}(-1)^{p的逆序对数}prodlimits_{i=1}^na_{i,p_i})​​​

    看右边那串东西,其实是从方阵中选出 (n)​ 个数,使得没有两个数在同一行或同一列,然后把它们乘起来。所以如果选出的数中有一个 (0) 就没有贡献了。

    排列的性质

    1. 交换两数,逆序对数的奇偶性改变
    2. (nge 2) 时,奇偶排列(逆序对数为奇 / 偶数的排列)各占一半

    行列式的性质

    1. (|M|=|M^T|)
    2. 交换两行,行列式反号
    3. 用一个数乘行列式的某行,等于用这个数乘此行列式
    4. 如果行列式中有两行成比例,则行列式等于 (0)(先把比例系数提出来,发现两行相同了,交换两行行列式不变。但根据性质 2,行列式反号了,所以只能为 (0)
    5. 若行列式中某一行是两组数之和,则这个行列式等于两个行列式之和,这两个行列式分别以这两组数为该行,而其余各行与原行列式对应各行相同。即:(left|egin{matrix}dots\a_{i,1}+b_{i,1},a_{i,2}+b_{i,2}dots a_{i,n}+b_{i,n}\dotsend{matrix} ight|=left|egin{matrix}dots\a_{i,1},a_{i,2}dots a_{i,n}\dotsend{matrix} ight|+left|egin{matrix}dots\b_{i,1},b_{i,2}dots b_{i,n}\dotsend{matrix} ight|)
    6. 将某一行的倍数加到另一行,行列式的值不变
    7. (left|egin{matrix}A~0\C~Bend{matrix} ight|=|A||B|)​,其中 (A,B)​​ 是方阵 (从选数的角度考虑)
    8. 一个矩阵的行列式可以按行展开,即:(left|egin{matrix}dots\a_{i,1},a_{i,2}dots a_{i,n}\dotsend{matrix} ight|=left|egin{matrix}dots\a_{i,1},0dots 0\dotsend{matrix} ight|+left|egin{matrix}dots\0,a_{i,2},0dots 0\dotsend{matrix} ight|+dots+left|egin{matrix}dots\0,dots 0,a_{i,n}\dotsend{matrix} ight|)​​​​​(还是从选数的角度理解,第 (i)​​​​​ 行只能选一个数,选 (a_{i,1},a_{i,2},dots,a_{i,n})​​​​​ 的方案是独立的)。进一步地,定义代数余子式:(A_{i,j}=(-1)^{i+j}|M_{i,j}|)​​​​​,其中 (M_{i,j})​​​​​ 是原矩阵删去第 (i)​​​​​ 行和第 (j)​​​​​ 列得到的矩阵。一个矩阵的行列式,等于它某一行中,每个元素乘上它的代数余子式的和。即:(|B|=sumlimits_{j=1}^nb_{i,j}A_{i,j}=(-1)^{i+j}b_{i,j}|M_{i,j}|)​​​​​​​(展开后,每个矩阵的第 (i)​​​​​ 行只有一个数,用 (i+j-2)​​​​​ 次交换邻行邻列把它交换到 ((1,1))​​​​​,然后用性质 7)
    9. 上(下)三角矩阵的行列式为其主对角线元素之积。

    行列式求值

    模板题

    现在考虑如何计算一个矩阵的行列式。观察到第 9 条性质,我们可以把矩阵消成上三角矩阵,同时注意符号的变化,然后直接得出答案。

    但当矩阵内都是整数时,仍会涉及实数运算,导致精度较低。考虑一种辗转相除的方法:每次选定两行 (i,j)​​,将第 (j)​​ 行尽可能多地减去第 (i)​​ 行,然后交换这两行,直到 (a_{i,i}=0)​。这样时间复杂度是 (O(n^3+n^2log V))​ 的。

    rep(i, 1, n) rep(j, i + 1, n) {
    	while(a[i][i]) {
    		t = a[j][i] / a[i][i];
    		rep(k, i, n) a[j][k] = (a[j][k] - a[i][k] * t % p + p) % p;
    		swap(a[i], a[j]);
    		ans = -ans;
    	}
    	swap(a[i], a[j]);
    	ans = -ans;
    }
    if(ans < 0) ans += p;
    rep(i, 1, n) (ans *= a[i][i]) %= p;
    

    3. 矩阵求逆

    模板题

    对于矩阵 (A),若存在矩阵 (B) 使得 (AB=I)(I) 是单位矩阵),则 (B)(A) 的逆,也可写作 (A^{-1})

    对矩阵进行高斯消元时,我们发现可以仅用初等行变换将矩阵变成单位矩阵,而每一种初等行变换都可以表示成一次矩阵乘法。即 (AP_1P_2dots P_k=I)。那么 (P_1P_2dots P_k) 不就是答案吗?

    我们可以在高斯消元时记录下所有操作,然后搞一个单位矩阵,再把这些操作做一遍。或者更方便地,我们在原矩阵右边添加一个单位矩阵,把左边消成单位矩阵,右边就求出了逆。

    若原矩阵不能消成单位矩阵,则原矩阵不可逆。

    n = read();
    rep(i, 1, n) rep(j, 1, n) a[i][j] = read();
    rep(i, 1, n) a[i][i + n] = 1;
    rep(i, 1, n) {
    	if(!a[i][i]) rep(j, i + 1, n) if(a[j][i]) { swap(a[i], a[j]); break; }
    	if(!a[i][i]) return puts("No Solution") & 0;
    	tmp = poww(a[i][i]);
    	rep(j, 1, n) if(i != j) {
    		t = a[j][i] * tmp % P;
    		rep(k, 1, n * 2) a[j][k] = (a[j][k] - a[i][k] * t % P + P) % P;
    	}
    	rep(j, i, n * 2) (a[i][j] *= tmp) %= P;
    }
    rep(i, 1, n) {
    	rep(j, n + 1, n * 2)
    		printf("%lld ", a[i][j]);
    	putchar(10);
    }
    

    4. 特征值与特征向量

    有时,对一个向量进行一次线性变换(左乘一个矩阵),这个向量方向不变,只是长度发生了变化,即 (Av=lambda v)​​​。也可以表示成 ((A-lambda I)v=0)​​

    对于一个矩阵 (A)​​​​,若存在数 (lambda)​​​​ 和向量 (v)​​​​ 使得 (Av=lambda v)​​​​,称 (lambda)​​​​ 为矩阵 (A)​​​​ 的 特征值(v)​​​​ 为 特征向量。同时定义 (f(x)=|xI-A|)​​​​ 为 特征多项式(|xI-A|=0)​​​​ 为 特征方程

    定理 (n) 阶矩阵 (A)(n) 个特征值,为其特征方程的 (n) 个根。特征值 (lambda)​ 对应的特征向量为 ((lambda I-A)x=0)​ 的非零解。

    注意一个特征值对应无穷多个特征向量,因为可以对向量进行数乘,仍满足定义。

    矩阵对角化

    相似矩阵:对于两个矩阵 (A,B)​,若存在可逆矩阵 (P)​ 使得 (P^{-1}AP=B)​,则 (A,B)​ 相似。

    考虑矩阵 (A) 和对角矩阵 (Lambda=left[egin{matrix}lambda_1\&lambda_2\&&ddots\&&&lambda_nend{matrix} ight]) 相似的条件。设矩阵 (P)(n) 个列向量构成即 (P=[p_1,p_2,dots,p_n]),且 (P)​ 可逆

    (A[p_1,p_2,dots,p_n]=[p_1,p_2,dots,p_n]Lambda)([Ap_1,Ap_2,dots,Ap_n]=[lambda_1p_1,lambda_2p_2,dots,lambda_np_n])

    那么 (Ap_i=lambda_ip_i)。这不就是特征值和特征向量的定义吗?

    于是有 (A=PLambda P^{-1})​​​,其中 (Lambda)​ 是由 (A)​ 的所有特征值构成的对角矩阵,(P)​​ 的第 (i)​ 列是特征值 (lambda_i)​​​ 对应的特征向量。

    于是我们可以快速计算一些矩阵的幂,(A^n=(PLambda P^{-1})^n=PLambda^nP^{-1})​。

    递推数列通项公式

    这里只讨论二阶齐次线性递推数列。

    首先我们可以直接用上文的结论。​比如斐波纳契转移矩阵 (left[egin{matrix}1~1\1~0end{matrix} ight])​​​​,特征方程 (left|egin{matrix}lambda-1~-1\-1~lambdaend{matrix} ight|=0)​​​​ 即 (lambda^2-lambda-1=0)​​​​,解得 (lambda=dfrac{1pmsqrt 5}{2})​​​​,并分别求出特征向量 ([1,dfrac{sqrt 5-1}{2}]^T,[1,-dfrac{sqrt 5+1}{2}]^T)​​​​​​。​然后一顿爆算求出 (P)​​​​​​ 的逆 (left[egin{matrix}dfrac{5+sqrt5}{10}~dfrac{sqrt5}{5}\dfrac{5-sqrt5}{10}~-dfrac{sqrt5}{5}end{matrix} ight])​​​​​​。把 (P,Lambda^n,P^{-1})​​​​​​ 依次乘起来,最后乘上 ([1,0]^T)​​​​​​,就可得出通项公式 (f_n=dfrac{sqrt 5}{5}left[(dfrac{1+sqrt5}{2})^n-(dfrac{1-sqrt5}{2})^n ight])​​。​

    这么麻烦,为什么不用生成函数呢

    考虑一个数列 (f_i=pf_{i-1}+qf_{i-2})​,其中 (f_0,f_1) 已知

    尝试构造等比数列:设存在 (a,b) 使得 (f_{i+1}-af_i=b(f_i-af_{i-1}))​,即 (f_{i+1}=(a+b)f_i-abf_{i-1})

    发现 (a,b)​ 是方程 (x^2-px-q=0)​ 的根。而这个方程就是转移矩阵的特征方程

    所以 ({f_{i+1}-af_i})​ 是公比为 (b)​ 的等比数列,有 (f_{i+1}-af_i=b^i(f_1-af_0))​。

    又发现 (a,b) 也满足 (f_{i+1}-bf_i=a(f_i-bf_{i-1}))

    所以 ({f_{i+1}-bf_i}) 是公比为 (a) 的等差数列,有 (f_{i+1}-bf_i=a^i(f_1-bf_0))​。​

    两式相减,得到 (f_i=dfrac{f_1-af_0}{b-a}b^i+dfrac{f_1-bf_0}{a-b}a^i)

    其实并不用每次推。可以设 (f_i=alpha a^i+eta b^i)​,解一个方程就完了

    比如斐波纳契数列,(a=dfrac{1+sqrt 5}{2},b=dfrac{1-sqrt 5}{2}),设 (f_i=alpha a^i+eta b^i),则 (egin{cases}f_0=alpha +eta=0\f_1=frac{1+sqrt 5}{2}alpha+frac{1-sqrt 5}{2}etaend{cases})

    解得 (alpha=dfrac{sqrt 5}{5},eta=-dfrac{sqrt 5}{5}),那么 (f_n=dfrac{sqrt 5}{5}left[(dfrac{1+sqrt5}{2})^n-(dfrac{1-sqrt5}{2})^n ight])​。​

    对于更高阶的情况,记个结论:设 (f_i=alpha a^i+eta b^i+gamma c^i+dots)​,列方程组​

    例题 - 块速递推

    常系数齐次线性递推

    模板题

    首先可以写出一个 (k imes k) 的转移矩阵:(A=left[egin{matrix}f_1~f_2~f_3~dots f_{k-1}~f_k\1~~~0~~~0~~dots~~~0~~~0\0~~~1~~~0~~dots~~~0~~~0\0~~~0~~~1~~dots~~~0~~~0\vdots~~~vdots~~~vdots~~~ddots~~~vdots~~~vdots\0~~~0~~~0~~dots~~~1~~~0end{matrix} ight])

    初始矩阵 (B=[a_{k-1},a_{k-2},dots,a_0]^T)​​,答案是 ((A^nB)_k)​​。

    凯莱-哈密顿定理:对于矩阵 (A)​​​,(f(x)=|xI-A|)​​​ 为其特征多项式,有 (f(A)=O)​​​,其中 (O)​​​ 是零矩阵。

    本题中,可以用行列式性质 7 和 8 计算出 (f(x)=x^k-f_1x^{k-1}-f_2^{k-2}-dots-f_k)

    那么只需计算 (g(x)=x^nmod f(x)=sumlimits_{i=0}^{k-1}g_ix^i)​,答案为 ((g(A)B)_k=(sumlimits_{i=0}^{k-1}g_iA^iB)_k=sumlimits_{i=0}^{k-1}g_i(A^iB)_k=sumlimits_{i=0}^{k-1}g_ia_i)​。

    计算 (g(x)) 可以用倍增 + 多项式取模。时间复杂度 (O(klog klog n))​。

  • 相关阅读:
    ZOJ 1217 eight
    COJ 1080 A simple maze
    八数码(双向广搜)
    HDOJ 1043 eight
    [HDOJ] 小兔的棋盘
    ZOJ 2110 Tempter of the Bone
    POJ 2406 Power Strings
    [HDOJ] goagain的超级数列
    COJ 1216 异或最大值
    八数码(IDA*)
  • 原文地址:https://www.cnblogs.com/creating-2007/p/15067424.html
Copyright © 2011-2022 走看看