从高斯消元到矩阵树定理
1. 高斯消元
-
前置技能,枚举主元法的高斯消元,即消第n个元的时候,每次选出绝对值最大一个方程对其他的进行消元。
-
但是常见的高斯消元模板并不能很好的解决,哪些元是变元以及哪些是确定解的问题。
-
假设方程有 n n n个未知数, m m m个方程,那么我们在高斯消元的同时记录一个变量 n o w now now,表示使用了 n o w now now个方程,注意考虑到第 n o w now now个方程发现第 i i i个变元可能无解,这时 n o w now now不++,因为它可能还有用。
-
如果使用的方程数小于未知变量数,说明可能无解或者存在自由元。
-
判断无解即变量用完了方程没用完 ,这是看剩下的方程存不存在 0 x = k ( k ! = 0 ) 0x=k(k!=0) 0x=k(k!=0)
-
判断一个变量是不是自由元,其实这个时候能解的一步就可以解出来,判断一下这一行是否有能解出来的即可。
-
代码如下
#include<iostream> #include<stdio.h> #include<string.h> #include<algorithm> #define maxn 405 using namespace std; double eps=1e-7; double myabs(double now) { return now>0.0 ? now : -now; } int n,m;// n个方程m个未知数 int vis[maxn]; double ans[maxn]; double a[maxn][maxn]; int gauss() { int now=1;//考虑到了第now个方程了 for(int i=1;i<=n && now<=m;i++,now++) { int row=now; for(int j=now+1;j<=m;j++) if(myabs(a[j][i])>myabs(a[row][i])) row=j; if(myabs(a[row][i])<=eps) { now--;//这里是因为第i个变量可能解不出来了,但是第now个方程依然可能有用 continue; } if(row!=i) for(int j=1;j<=n+1;j++) swap(a[i][j],a[row][j]); for(int j=1;j<=m;j++)//全消了 if(myabs(a[j][i])>eps && j!=now) { double temp=a[j][i]/a[now][i]; for(int k=i;k<=n+1;k++) a[j][k]-=temp*a[now][k]; } } //考虑无解 for(int i=now;i<=m;i++) { if(myabs(a[i][n+1])>eps) { return 0; } } if(now<=n)//用了的方程少于变元数 { for(int i=1;i<=now-1;i++) { int cnt=0,pos=0; for(int j=1;j<=n;j++) if(myabs(a[i][j])>eps && !vis[j]) { cnt++; pos=j; } if(cnt>1) continue; ans[pos]=a[i][n+1]; for(int j=1;j<=n;j++) { if(j!=pos && myabs(a[j][i])>1e-6) { ans[pos]-=a[i][j]*ans[j]; } } ans[pos]=ans[pos]/a[i][pos]; vis[pos]=1; } } else { for(int i=1;i<=n;i++) ans[i]=a[i][n+1]/a[i][i],vis[i]=1; } return 1; } int main() { scanf("%d",&n); m=n; for(int i=1;i<=m;i++) for(int j=1;j<=n+1;j++) scanf("%lf",&a[i][j]); if(!gauss()) { printf("No Solution\n"); return 0; } for(int i=1;i<=n;i++) { if(!vis[i]) { printf("%d not determined\n",i); } else { printf("%.2lf\n",ans[i]); } } }
2.矩阵的逆
- 学过高等代数的人都知道,给原矩阵右边添上一个单位矩阵,将原矩阵高斯消元为单位矩阵,右边的矩阵即为原矩阵的逆。
3.行列式及特殊矩阵行列式求法
-
学过高等代数的人都知道,将矩阵用线性变换的方法化成对角矩阵之后,对角线元素相乘,即为行列式。但是是用高斯消元的时候会交换两行,这样的话会使得行列式的值乘 − 1 -1 −1,记录一下即可。
-
行列式可以按行展开,公式为 ∑ j = 1 m ( − 1 i + j ) ∗ A i , j , A i , j 为 去 掉 第 i 行 第 j 列 的 行 列 式 \sum_{j=1}^m(-1^{i+j})*A_{i,j},A_{i,j}为去掉第i行第j列的行列式 ∑j=1m(−1i+j)∗Ai,j,Ai,j为去掉第i行第j列的行列式
-
特殊矩阵行列式求法
-
利用范德蒙行列式 D n = ∏ i < j ( x j − x i ) D_n=\prod_{i<j}(x_j-x_i) Dn=∏i<j(xj−xi)
D n = ∣ 1 1 ⋯ 1 x 1 x 2 ⋯ x n x 1 2 x 2 2 ⋯ x n 2 ⋯ ⋯ ⋯ ⋯ x 1 n − 1 x 2 n − 1 ⋯ x n n − 1 ∣ D_n=\begin{vmatrix}1 & 1 & {\cdots} & 1 &\\ {x_1}& {x_2} & {\cdots} &{x_n} &\\ x_1^2 & x_2^2 & \cdots & x_n^2 & \\ \cdots& \cdots& \cdots &\cdots & \\ x_1^{n-1}& x_2^{n-1} & \cdots & x_n^{n-1} & \\\end{vmatrix} Dn=∣∣∣∣∣∣∣∣∣∣1x1x12⋯x1n−11x2x22⋯x2n−1⋯⋯⋯⋯⋯1xnxn2⋯xnn−1∣∣∣∣∣∣∣∣∣∣ -
三对角行列式,直接展开得到递推关系 D n = { ( n + 1 ) a n , a = b a n + 1 − b n + 1 a − b , a ≠ b D_n=\left\{\begin{matrix} (n+1)a^n, & a=b\\ \frac {a^{n+1}-b^{n+1}}{a-b},&a\neq b \end{matrix}\right. Dn={(n+1)an,a−ban+1−bn+1,a=ba=b
D n = ∣ a + b a b 1 a + b a b ⋯ ⋯ 1 a + b a b 1 a + b ∣ D_n=\begin{vmatrix} a+b& ab & & & & \\ 1& a+b & ab & & & \\ & & \cdots& \cdots & & \\ & & & 1&a+b & ab\\ & & & & 1&a+b \end{vmatrix} Dn=∣∣∣∣∣∣∣∣∣∣a+b1aba+bab⋯⋯1a+b1aba+b∣∣∣∣∣∣∣∣∣∣ -
箭型行列式,即只有两条边和对角线上有值的行列式。把第 i i i列加到第1行,把第1列的第i行消成0。
-
除对角线外其他元素相等,或其他元素按行成比例,用第一行乘比例系数去减其他行。
-
两条线带几个点的行列式,直接展开递推即可。
-
4.矩阵树定理
- 矩阵树定理主要求解三类问题,给无向图求生成树数量,给有向图和一个点求以这个点为根的内向树和外向树的数量。
- 一般需要构造两个矩阵 S 1 , S 2 S_1,S_2 S1,S2分别为联通矩阵和度数矩阵。
- 构造方法:
- 给无向图求生成树数量, S 1 ( i , j ) S_1(i,j) S1(i,j)为 i i i与 j j j之间的边数, S 2 ( i , i ) S_2(i,i) S2(i,i)为第 i i i个点的度数
- 以一个点为根的内向树, S 2 ( i , j ) S_2(i,j) S2(i,j)为 i i i到 j j j之间的边数, S 2 ( i , i ) S_2(i,i) S2(i,i)为第 i i i个点的入度
- 以一个点为根的外向树, S 2 ( i , j ) S_2(i,j) S2(i,j)为 i i i到 j j j之间的边数, S 2 ( i , i ) S_2(i,i) S2(i,i)为第 i i i个点的出度
- 求解方法:先得到矩阵
T
=
S
2
−
S
1
T=S_2-S_1
T=S2−S1
- 给无向图求生成树数量,任意删去一行一列(一般为最后一行一列),求行列式
- 以一个点为根的内向树,删去给定点所在行所在列,求行列式
- 以一个点为根的外向树,删去给定点所在行所在列,求行列式