【模板】矩陣樹定理
阿新 • • 發佈:2018-12-11
對了有一道假題目
解析:
先明確幾個定義。
對於一個圖,定義其度數矩陣為,為一個的矩陣,滿足當的時候,,而大對角線上的元素值為節點的度數。
對於一個圖,定義其鄰接矩陣為,為一個的矩陣,滿足元素等於之間直接連線的邊數,也稱為接數。
對於一個圖,定義其矩陣()如下,為一個的矩陣,滿足對於 。
定理內容描述如下。
對於一個圖,其生成樹個數等於。其中表示該矩陣行列式的值。
證明是個很妙妙的東西。
然而太長了不想寫
那就主要講一講怎麼求一個矩陣的行列式吧。
首先行列式的定義要補充一下。
一個方陣的行列式記為或。
把一個元素所在行列劃去後(不是置為0,而是整行整列消去),剩餘的矩陣的行列式稱為元素的餘子式,記作,而稱作的代數餘子式,而行列式的值定義如下
好的上面這個完全不說人話的表述方式你看懂了嗎?
接下來是一個稍微說人話一點的表述方式。
以一個的方陣為例。 就是這個矩陣中 綠色的數之積+藍色數之積+橙色數之積+紅色數之積,
上面的結果減去這個矩陣中 綠色的數之積+藍色數之積+橙色數之積+紅色數之積, 上面的差的絕對值就是矩陣行列式的值。
其他大小的矩陣行列式以此類推。
於是行列式就有一些奇奇怪怪的性質。 比如一行(列),加上或減去另一行(列)每個元素的相同倍數,行列式的值不變。(證明可能什麼時候才會補吧)
那麼我們就可以利用高斯消元將當前矩陣消成一個上三角矩陣,那麼就可以輕易求出行列式的值了。
其行列式的值就變成了對角線上的所有值之積。 證明很簡單,因為這時候其他地方的積的式子中都含有至少一個元素為0,那麼有貢獻的就只剩下這條大對角線了。
程式碼:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc getchar
#define pc putchar
#define cs const
inline
int getint(){
re int num=0;
re char c;
while(!isdigit(c=gc()));
while(isdigit(c))num=(num<<1)+(num<<3)+(c^48),c=gc();
return num;
}
double a[13][13];
inline
double gauss(int n){
for(int re i=1;i<=n;++i){
int pos=i;
for(int re j=i+1;j<=n;++j){
if(fabs(a[j][i])>fabs(a[pos][i]))pos=j;
}
if(fabs(a[pos][i])<=1e-6)return 0;
if(pos!=i)swap(a[pos],a[i]);
for(int re j=i+1;j<=n;++j){
double tmp=a[j][i]/a[i][i];
for(int re k=1;k<=n;++k){
a[j][k]-=a[i][k]*tmp;
}
}
}
double ret=1;
for(int re i=1;i<=n;++i){
ret*=a[i][i];
}
return fabs(ret);
}
signed main(){
int T=getint();
while(T--){
int n=getint(),m=getint();
memset(a,0,sizeof a);
while(m--){
int u=getint(),v=getint();
a[u][u]+=1,a[v][v]+=1;
a[u][v]-=1,a[v][u]-=1;
}
printf("%.0lf\n",gauss(n-1));
}
return 0;
}