BZOJ传送门
洛谷传送门
解析:
其实
K
i
r
c
h
o
f
f
Kirchoff
Kirchoff的无向图矩阵本来就是有向图矩阵的一个扩展。所以这里仅将有向图的
K
i
r
c
h
o
f
f
Kirchoff
Kirchoff矩阵作一个简单的阐述,详细证明请参考其他
d
a
l
a
o
dalao
dalao的博客。(才不是因为我看网上证明都这么多了懒得写呢)
一条有向边 < u , v > <u,v> <u,v>在 K i r c h o f f Kirchoff Kirchoff矩阵上我们将 C v , v C_{v,v} Cv,v加1,因为这是入度,并且在 C v , u C_{v,u} Cv,u上减一。
最后我们要计算的是以某个节点为根的树形图的个数,我们将这个节点编号的一行一列去掉,计算剩余部分的行列式就行了。
其实会了这道题再回去看无向图的 M a t r i x T r e e Matrix Tree MatrixTree定理就觉得一切都明白了许多。
所以这里为了方便,将所有节点编号-1,算出矩阵去掉第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;
re char c;
while(!isdigit(c=gc()));num=c^48;
while(isdigit(c=gc()))num=(num<<1)+(num<<3)+(c^48);
return num;
}
cs int mod=10007,N=251;
struct matrix{
int arr[N][N];
int *cs operator[](cs int &offset){
return arr[offset];
}
int matrix_tree(int n){
for(int re i=1;i<=n;++i)
for(int re j=1;j<=n;++j)arr[i][j]=(arr[i][j]%mod+mod)%mod;
int res=1;
for(int re i=1;i<=n;++i){
for(int re j=i+1;j<=n;++j){
while(arr[j][i]){
int tmp=arr[i][i]/arr[j][i];
for(int re k=i;k<=n;++k)arr[i][k]=(arr[i][k]-arr[j][k]*tmp%mod+mod)%mod;
for(int re k=i;k<=n;++k)swap(arr[i][k],arr[j][k]);
res=mod-res;
}
}
res=(res*arr[i][i])%mod;
}
return res;
}
}C;
int n,m;
signed main(){
n=getint();
m=getint();
for(int re i=1;i<=m;++i){
int v=getint()-1;
int u=getint()-1;
++C[v][v];
--C[v][u];
}
cout<<C.matrix_tree(n-1);
return 0;
}