从高斯消元到矩阵树定理

从高斯消元到矩阵树定理

1. 高斯消元

  1. 前置技能,枚举主元法的高斯消元,即消第n个元的时候,每次选出绝对值最大一个方程对其他的进行消元。

  2. 但是常见的高斯消元模板并不能很好的解决,哪些元是变元以及哪些是确定解的问题。

  3. 假设方程有 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不++,因为它可能还有用。

  4. 如果使用的方程数小于未知变量数,说明可能无解或者存在自由元。

  5. 判断无解即变量用完了方程没用完 ,这是看剩下的方程存不存在 0 x = k ( k ! = 0 ) 0x=k(k!=0) 0x=k(k!=0)

  6. 判断一个变量是不是自由元,其实这个时候能解的一步就可以解出来,判断一下这一行是否有能解出来的即可。

  7. 代码如下

    #include
    #include
    #include
    #include
    #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.矩阵的逆

  1. 学过高等代数的人都知道,给原矩阵右边添上一个单位矩阵,将原矩阵高斯消元为单位矩阵,右边的矩阵即为原矩阵的逆。

3.行列式及特殊矩阵行列式求法

  1. 学过高等代数的人都知道,将矩阵用线性变换的方法化成对角矩阵之后,对角线元素相乘,即为行列式。但是是用高斯消元的时候会交换两行,这样的话会使得行列式的值乘 − 1 -1 1,记录一下即可。

  2. 行列式可以按行展开,公式为 ∑ 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,jij

  3. 特殊矩阵行列式求法

    1. 利用范德蒙行列式 D n = ∏ i < j ( x j − x i ) D_n=\prod_{iDn=i<j(xjxi)
      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=1x1x12x1n11x2x22x2n11xnxn2xnn1

    2. 三对角行列式,直接展开得到递推关系 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,aban+1bn+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+bab1a+b1aba+b

    3. 箭型行列式,即只有两条边和对角线上有值的行列式。把第 i i i列加到第1行,把第1列的第i行消成0。

    4. 除对角线外其他元素相等,或其他元素按行成比例,用第一行乘比例系数去减其他行。

    5. 两条线带几个点的行列式,直接展开递推即可。

4.矩阵树定理

  1. 矩阵树定理主要求解三类问题,给无向图求生成树数量,给有向图和一个点求以这个点为根的内向树和外向树的数量。
  2. 一般需要构造两个矩阵 S 1 , S 2 S_1,S_2 S1,S2分别为联通矩阵和度数矩阵。
  3. 构造方法:
    1. 给无向图求生成树数量, 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个点的度数
    2. 以一个点为根的内向树, 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个点的入度
    3. 以一个点为根的外向树, 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个点的出度
  4. 求解方法:先得到矩阵 T = S 2 − S 1 T=S_2-S_1 T=S2S1
    1. 给无向图求生成树数量,任意删去一行一列(一般为最后一行一列),求行列式
    2. 以一个点为根的内向树,删去给定点所在行所在列,求行列式
    3. 以一个点为根的外向树,删去给定点所在行所在列,求行列式

你可能感兴趣的:(从高斯消元到矩阵树定理)