1. 程式人生 > >Matrix-Tree定理(1)----矩陣的行列式

Matrix-Tree定理(1)----矩陣的行列式

菜雞博主開始看matrix tree定理辣!

開啟editorial,發現是生成樹計數相關,要用matrix tree定理,然後就一臉懵逼(智力-=2),決定學習matrix tree定理這個神奇的東西。

以下內容純屬博主口胡,不足之處希望dalao予以指出與更正。

前置技能:矩陣的行列式 (線代大佬們請手動忽略)

對於矩陣A[n][n],det(A)=sigma(sign*(A[1][p1]*A[2][p2]*...*A[n][pn])).

其中,p1....pn是1....n的一個排列,而sign=(-1)^( inv(p) mod 2),inv(p)=排列p中的逆序對數量.

矩陣行列式的一些性質:

1. 一個矩陣行列互換(A'[i][j]=A[j][i])得到矩陣A’,det(A)=det(A')

    這個性質,根據行列式的定義,顯然成立。

2.互換行列式兩行或兩列的位置,det(A')=-det(A).

   若交換了i,j兩行,考慮對於A矩陣的排列p=p1,p2...pi...pj....pn,不考慮符號,其對答案的貢獻為s1=A[1][p1]*A[2][p2]*....*A[n][pn].

                                  再考慮對於A’矩陣的排列p‘=p1,p2....pj...pi....pn,不考慮符號,其對答案的貢獻s2=A'[1][p1]*...A'[i][pj]*...*A'[j][pi]*....*A'[n][pn].

   因為只有i,j兩行發生了交換,顯然有s1=s2,而兩個排列p與p’只有在i,j位置發生了互換,此時逆序對的奇偶性發生變化(對於中間的數分類討論即可證明),sign符號相反.

   由此就可以得出結論2.

   一個很妙的推論:若矩陣第i行與第j行的值完全相同,det=0

3.矩陣A中某一行的元素全部乘以常數k,則det(A')=k*det(A).

  由行列式的定義,顯然成立。

4. 由2,3可以得到,若存在1<=i,j<=n,k為實數滿足A[i][l]=k*A[j][l]對於所有1<=l<=n均成立,則det(A)=0.

5. 將第i行所有元素加上任意其他行元素的實數倍,det(A)不變.

    證明: 考慮排列p1,p2,p3.....pn對於答案的貢獻,

             原始矩陣:s1=sign*A[1][p1]*A[2][p2]*....*A[n][pn],

             新矩陣: s2=sign*A[1][p1]*A[2][p2]*...*A[n][pn]+sign*k*A[1][p1]*A[2][p2]*..*A[j][pi]*..A[n][pn].

    而sigma(s2-s1)=0,所以得證(Why?---------轉至定理4)

有了這些,下面就將介紹一種O(n^3)求解矩陣行列式的一種辦法,

這種辦法類似於高斯消元,通過將矩陣消成上三角矩陣進行行列式的求解,

對於上三角矩陣行列式的求解,顯然det(A)=A[1][1]*A[2][2]*....*A[n][n].

具體步驟: 對於第i行,我們希望將滿足i+1<=j<=n的A[j][i]的值變為0 。

                 所以考慮過程gauss(i,j)表示將第j行第i項消為0。

                 由定理5,可以考慮構造實數k使得A’[j][i]=0.

                                    解方程A[j][i]+k*A[i][i]=0.

                                    則k=(-A[j][i])/A[i][i].

                 通過定理5,我們可以將第j行元素加上第i行同列元素的k倍從而實現消元過程。

                 這樣就可以O(n^3)實現矩陣行列式的求解。

附上博主的程式碼(博主碼風不是很和諧,希望dalao們不要吐槽):

注:此程式碼並沒有經過檢驗,若有問題,還望大牛指正!

#include <bits/stdc++.h>
#define eps 1e-8
using namespace std;
double a[305][305];
int n;
inline double calc()
{int i,j,k;
for (i=1;i<=n;i++)
{if (a[i][i]<eps&&a[i][i]>-eps) {return 0;}
for (j=i+1;j<=n;j++)
{double rat=(-a[j][i])/a[i][i];
for (k=i;k<=n;k++)
{a[j][k]+=a[i][k]*rat;}
}
}
double ret=1;
for (i=1;i<=n;i++)
{ret*=a[i][i];}
return ret;
}
int main (){
	int i,j;
	scanf ("%d",&n);
	for (i=1;i<=n;i++)
	{for (j=1;j<=n;j++)
	{scanf ("%lf",&a[i][j]);}
	}
	printf ("%.6lf\n",calc());
	return 0;
}


嗯,沒錯,有關行列式的部分就是這樣,

畢竟博主太弱,一天只能看這麼點內容,

有關matrix tree定理的介紹就請看下一篇辣!