problem
给定一个有 n n n 个点, m m m 条边的有向图,求以 1 1 1 为根的外向生成树数量。
数据范围: 1 ≤ n ≤ 250 1\le n\le 250 1≤n≤250, 1 ≤ m ≤ n ( n − 1 ) 1\le m\le n(n-1) 1≤m≤n(n−1)。
solution
这貌似是矩阵树定理的模板题。
构造基尔霍夫矩阵时,由于是外向树,那么就是入度矩阵 − - − 邻接矩阵(如果是内向树则是出度矩阵 − - − 邻接矩阵)。
由于要以 1 1 1 为根,那么要把第 1 1 1 行第 1 1 1 列删掉。
然后求个行列式,用高斯消元解即可。
时间复杂度 O ( n 3 ) O(n^3) O(n3)。
code
#include<bits/stdc++.h>
using namespace std;
const int N=255,P=1e4+7;
int n,m,A[N][N],x[N];
int add(int x,int y) {return x+y>=P?x+y-P:x+y;}
int dec(int x,int y) {return x-y< 0?x-y+P:x-y;}
int mul(int x,int y) {return x*y>=P?x*y%P:x*y;}
int power(int a,int b){
int ans=1;
for(;b;b>>=1,a=mul(a,a)) if(b&1) ans=mul(ans,a);
return ans;
}
int Guass(){
int ans=1;
for(int i=2,k=2;i<=n;k=++i){
for(int j=i+1;j<=n;++j)
if(A[j][i]>A[k][i]) k=j;
if(k!=i) swap(A[i],A[k]),ans=P-ans;
if(!A[i][i]) return 0;
int inv=power(A[i][i],P-2);
for(int j=i+1;j<=n;++j)
for(int k=i+1;k<=n+1;++k)
A[j][k]=dec(A[j][k],mul(mul(A[i][k],A[j][i]),inv));
}
for(int i=2;i<=n;++i) ans=mul(ans,A[i][i]);
return ans;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1,x,y;i<=m;++i){
scanf("%d%d",&x,&y),A[x][x]++,A[y][x]--;
}
for(int i=1;i<=n;++i)
for(int j=1;j<=n;++j)
if(A[i][j]<0) A[i][j]+=P;
printf("%d\n",Guass());
return 0;
}