由於過於難啃(懶)於是來記個筆記。
start
首先一個結論:
對於一個無向圖 G ,它的生成樹個數等於其基爾霍夫矩陣(Kirchhoff矩陣)任何一個N-1階主子式的行列式的絕對值。
基爾霍夫矩陣可以由度數矩陣D-鄰接矩陣A得到。
度數矩陣D:
\[D_{i,j}=[i==j]in_i \]
其中\(in_x\)表示x點度數。
鄰接矩陣A:
\[A_{i,j}=[i!=j]w_{i,j} \]
其中\(w_{i,j}\)表示i,j兩點之間邊數。
不會證,記就完事了。
N-1階主子式就是這個矩陣去掉某一行某一列之后的新矩陣。
然后就要求行列式了。
先是有個開始的柿子:
\[det(K)=\sum_p(-1)^{\tau (p)}\prod\limits_{i=1}^{n}K_{i,p_i} \]
其中\({\tau (p)}\)表示排列\(p\)中逆序對數,也說明要求從K中任意選的n個數行列互不相同。
暴力求解復雜度過高於是考慮優化。
行列式的性質
- 交換一個矩陣的兩行,行列式變號。
這個很好證,首先K值肯定不變,然而交換了兩行\(i,j\)之后,夾在i,j之間的變化量也一定是變一個偶數,但是ij之間的就變了一次,於是變號了。 - 如果矩陣有兩行(列)完全相同,則行列式為 0
由1可得交換兩行之后變號,但是交換之后整個矩陣不變所以只能是0 - 如果矩陣的某一行(列)中的所有元素都乘以同一個數k,新行列式的值等於原行列式的值乘上數k。
直接把柿子中提出來一個K即可。
3.5 如果矩陣的某一行(列)中的所有元素都有一個公因子k,則可以把這個公因子k提到行列式求和式的外面。 - 如果矩陣有兩行(列)成比例(比例系數k),則行列式的值為 0
可以把大的一行提出來一個k,然后由2得到一定是0 - 如果把矩陣的某一行(列)加上另一行(列)的k倍,則行列式的值不變。
可以把新的求和柿子拆成兩個柿子,一個是原來的柿子,一個是新加的k倍的柿子,由4得到后者一定是0,所以值不變。
求行列式
由上面幾個性質,我們就可以求行列式了。
先偷個圖:
沒錯,是個上三角矩陣。那么它的行列式就是對角線的乘積,因為只有這時才能滿足每一項都不是0.
那么我們如何把一個普通矩陣變成一個上三角矩陣呢?
看看性質5,沒錯,我們可以高斯消元!然后就可以愉快地求矩陣了!
對於計算過程中不允許出現實數的情況,可以采用輾轉相除法。也可以使用逆元(如果有的話)
最后放個輾轉相除的板子。
while(a[j][i]){
int t=a[j][i]/a[i][i];
F(k,i,n)a[i][k]-=1ll*a[j][k]*t%mod,a[i][k]+=a[i][k]<0?mod:0,a[i][k]-=a[i][k]>=mod?mod:0;
std::swap(a[i],a[j]);ans=mod-ans;
}