前言 MatrixTree定理是用來解決生成樹計數問題的有利工具 比如說 "這道題" MatrixTree定理的演算法流程也非常簡單 我們記矩陣$A$為無向圖的度數矩陣 記矩陣$D$為無向圖的鄰接矩陣 $A$矩陣是除了對角線之外各個點值都為$0$的矩陣,$A[i][i]$表示$i$號點的度數 $D$矩 ...
前言
MatrixTree定理是用來解決生成樹計數問題的有利工具
比如說這道題
MatrixTree定理的演算法流程也非常簡單
我們記矩陣\(A\)為無向圖的度數矩陣
記矩陣\(D\)為無向圖的鄰接矩陣
\(A\)矩陣是除了對角線之外各個點值都為\(0\)的矩陣,\(A[i][i]\)表示\(i\)號點的度數
\(D\)矩陣記錄兩點之間的度數,\(D[i][j]\)表示\(i\)號點與\(j\)號點之間的邊數
MatrixTree定理
我們記矩陣\(G=A-D\)
那麼\(G\)的所有不同生成樹的個數等於\(G\)的任何一個 \(n-1\) 階主子式的行列式的絕對值
實現
MatrixTree定理的實現非常簡單
- 計算出\(D\)矩陣
- 後對其進行高斯消元
- 把消元後的矩陣的對角線乘起來
- 輸出
代碼
就是上面那道題目的代碼
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
using namespace std;
const int MAXN=3001;
const double eps=1e-12;
inline int read()
{
char c=getchar();int x=0,f=1;
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
return x*f;
}
double G[MAXN][MAXN],a[MAXN][MAXN];
char s[MAXN][MAXN];
int xx[5]={0,-1,+1,0,0};
int yy[5]={0,0,0,-1,+1};
int N,M;
int dcmp(int x)
{
if(x<=eps||x>=-eps) return 0;
else return x<0?-1:1;
}
void Gauss()
{
N--;
for(int i=1;i<=N;i++)//每一行
{
int mx=i;
for(int j=i+1;j<=N;j++)//下麵的每一行
if(dcmp(G[mx][i]-G[j][i])<0) mx=j;
if(mx!=i) swap(G[i],G[mx]);
if(!G[i][i]) {printf("0\n");return ;}
for(int j=i+1;j<=N;j++)
{
double t=G[j][i]/G[i][i];
for(int k=i;k<=N+1;k++)
G[j][k]-=t*G[i][k];
}
}
double ans=1;
for(int i=1;i<=N;i++) ans=ans*G[i][i];
printf("%.0f\n",abs(ans));
}
int main()
{
int T=read();
while(T--)
{
memset(G,0,sizeof(G));
N=read(),M=read();
for(int i=1;i<=M;i++)
{
int x=read(),y=read();
G[x][x]++;G[y][y]++;
G[x][y]--;G[y][x]--;
}
Gauss();
}
return 0;
}