大佬1博客:https://www.cnblogs.com/zj75211/p/8039443.html
大佬2博客:https://www.cnblogs.com/yangsongyi/p/10697176.html
三个定理:
- 给出无向图,求这个图的生成树个数
- 给出有向图和其中的一个点,求以这个点为根的生成外向树个数
- 给出有向图和其中一个点,求以这个点为根的生成内向树个数
对于上述三个定理,首先都是需要构造基尔霍夫Kirchhoff矩阵,构造方法如下:
基尔霍夫Kirchhoff矩阵 K = 度数矩阵 D - 邻接矩阵 A
对于上述三个定理,分别求解:
- D矩阵:度数,A矩阵:无向图,删除任意第 r 行和第 r 列后的行列式的绝对值即为答案
- D矩阵:入度,A矩阵:有向图,假设点为 x ,则删除第 x 行和第 x 列后的行列式的绝对值即为答案
- D矩阵:出度,A矩阵:有向图,假设点为 x ,则删除第 x 行和第 x 列后的行列式的绝对值即为答案
最后挂个高斯消元求解行列式的模板,时间复杂度为 n^3 ,空间复杂度为 n^2,允许取模
代码:
const int N=110;
const int mod=998244353;
LL a[N][N];
LL q_pow(LL a,LL b)
{
LL ans=1;
while(b)
{
if(b&1)
ans=ans*a%mod;
a=a*a%mod;
b>>=1;
}
return ans;
}
LL Gauss(int n)
{
LL ans=1;
for(int i=2;i<=n;i++)
{
for(int j=i+1;j<=n;j++)
if(!a[i][i]&&a[j][i])
{
ans=-ans;
swap(a[i],a[j]);
break;
}
LL inv=q_pow(a[i][i],mod-2);
for(int j=i+1;j<=n;j++)
{
LL temp=a[j][i]*inv%mod;
for(int k=i;k<=n;k++)
a[j][k]=(a[j][k]-a[i][k]*temp%mod+mod)%mod;
}
ans=ans*a[i][i]%mod;
}
return ans;
}