1. 程式人生 > 實用技巧 >「學習筆記」矩陣樹定理

「學習筆記」矩陣樹定理

因為不想改題或者動腦子了,所以去學習了矩陣樹定理


首先附上一些行列式的知識:

求一個 \(n \times n\) 的矩陣的行列式等價於求對於所有長度為 \(n\) 的排列 \(P=\{p_1,p_2,p_3\dots p_n\}\)

\({det(K)=}\sum_{P}^{ }\;{(}{(-1)}^{\tau{(P)}}\times{K}_{1,p1}\times{K}_{2,p_2}\times{K}_ {3,p_3}\times\cdots\times{K}_ {n,p_n}{)}\)

或者理解成所有全排列直接對於當前行的對應位置乘積,然後加減考慮排列的逆序對的奇偶性

同時有幾個性質:

\((1)\) 交換兩行或者兩列,行列式取反

\((2)\) 如果兩行或者兩列有倍數關係(\(1\) 倍也算),那麼行列式的值為 \(0\)

\((3)\) 任意一行或者一列乘上任意數加到任意另一行上,行列式不變

\((4)\) 上三角矩陣的行列式值是對角線乘積

(上面的行列式都是指行列式的值,下同)


定義基爾霍夫矩陣為度數矩陣減掉鄰接矩陣

那麼有如下幾個定理

\((1)\) 去掉矩陣的任意一行和一列之後得到的餘子式的行列式是當前圖的生成樹個數

不太會證,不過好背就行了

\((2)\) 求有向圖的定跟的生成內向樹的個數,度數矩陣只記錄出度,然後消元的時候去掉根所在的行和列即可

\((3)\)

求生成外向樹的個數,度數矩陣只記錄入度,消元還是去掉根所在的行和列

要求矩陣樹的邊權乘積的話直接把度數改成相應的邊權和,然後鄰接矩陣加上權就行了


其實本質好像並不複雜,但是魔鬼在變式:

高斯消元不能取模

這裡考慮輾轉相除即可

while(a[j][i]){
 	int d=a[i][i]/a[j][i];
	for(reg int k=i;k<=cnt-1;++k) a[i][k]=((a[i][k]-a[j][k]*d)%mod+mod)%mod;
	swap(a[i],a[j]); ans=del(mod,ans);
}

別的慢慢打例題慢慢積累吧

\(1.\) 輪狀病毒

建圖一眼,然後交上去 \(50\)

,然後發現得高精

並不會高斯消元套著高精,就去打了表,扔到 \(oeis\) 裡面抄了個遞推式然後過掉了

具體遞推式是:

\[f_i=3f_{i-1}-f_{i-2}+2 \]

證明在這個部落格裡面寫得很詳細:link

其實大概思路消掉第一行第一列之後維護剩下的行列式求法

然後發現再刪掉餘子式的第一行第一列就只有五個數

分別記貢獻得到 \(Mat_A,Mat_B\) 然後硬推出的

這裡有一個小收穫:矩陣行列式等於其任意行或者列的元素乘上其代數餘子式的和

\(2.\) 黑暗前的幻想鄉

套上板子之後簡單容斥即可

\(3.\) 重建

先手玩樣例發現直接乘是不行的,還得乘上別的不存在的概率

直接把 \(\frac{p_e}{1-p_e}\) 扔進去就行了,然後最後外面乘個權值即可

\(4.\) 最小生成樹計數

先跑個 \(Kruskal\) ,如果環上的最大值是這條邊的權值那麼就是加進去

然後跑個矩陣樹定理


顯然這個做法只有在環上的邊權都一樣的時候成立

那麼接著考慮 \(kruskal\) 的過程,每連上一個邊就是說合並兩個聯通塊

那麼邊的代替也只能是代替權值相同的邊,那麼就可以把所有的同權值的邊砍掉之後跑 \(kruskal\)

然後聯通塊縮成一個點,再連上所有縮完的跑矩陣樹就行了,最後把答案一乘就完事了

然後我是真的sb,跟著學怎麼把陣列開小

\(4.\) 生成樹

好像是個板子就扔掉了