Luogu6178 【模板】Matrix-Tree 定理
https://www.luogu.com.cn/problem/P6178
矩阵树定理
记住结论\(QAQ\)
\(D\)为度数矩阵
\(A\)为邻接矩阵
外向树:边的方向为根指向子节点
内向树:边的方向为子节点指向根
若边权为\(cost\)
那么所有生成树的边权乘积的和如下:
无向图:
\(D\):存在边\(i-j\),则\(D_{i,i}+=cost,D_{j,j}+=cost\),对于\(D_{i,j}(i \ne j)\),\(D_{i,j}=0\)
\(A\):存在边\(i-j\)则\(a_{i,j}=a_{j,i}=cost\),否则\(a_{i,j}=a_{j,i}=0\)
有向图:
\(D\):存在边\(i \rightarrow j\),则:
外向树:\(D_{j,j}+=cost\)
内向树:\(D_{i,i}+=cost\)
\(A\):存在边\(i \rightarrow j\)则\(a_{i,j}=cost\),否则\(a_{i,j}=0\)
设\(C=D-A\)
无向图中:
答案为\(C\)对于任意的\(r\),划去第\(r\)行,第\(r\)列得到的\(n-1\)阶余子式的行列式值
有向图中:
答案为\(C\)对于根节点\(r\),划去第\(r\)行,第\(r\)列得到的\(n-1\)阶余子式的行列式值
若要计算生成树个数,设边权为\(1\)即可
注意,计算行列式时,高斯-约旦消元要保留行列式的上三角(改一下参数就好了),而且交换两行时,行列式的值要变号
\(C++ Code:\)
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#define ll long long
#define N 305
#define p 1000000007
using namespace std;
int x,y,z,n,m,t;
ll a[N][N],ans=1;
ll ksm(ll x,ll y)
{
ll ans=1;
while (y)
{
if (y & 1)
ans=ans*x%p;
x=x*x%p;
y >>=1;
}
return ans;
}
#define inv(x) ksm(x,p-2)
void Gauss()
{
for (int i=2;i<=n;i++)
{
int mx=i;
for (int j=i+1;j<=n;j++)
if (!a[i][i] && a[j][i])
{
mx=j;
break;
}
if (!a[mx][i])
{
ans=0;
return;
}
if (mx!=i)
{
for (int j=1;j<=n;j++)
swap(a[mx][j],a[i][j]);
ans=-ans;
}
for (int j=i;j<=n;j++)
if (j!=i)
{
ll t=a[j][i]*inv(a[i][i])%p;
for (int k=i;k<=n;k++)
(a[j][k]-=t*a[i][k])%=p;
}
}
}
int main()
{
scanf("%d%d%d",&n,&m,&t);
for (int i=1;i<=m;i++)
{
scanf("%d%d%d",&x,&y,&z);
switch (t)
{
case 0:
(a[x][x]+=z)%=p;
(a[y][y]+=z)%=p;
(a[x][y]-=z)%=p;
(a[y][x]-=z)%=p;
break;
case 1:
(a[y][y]+=z)%=p;
(a[x][y]-=z)%=p;
break;
}
}
Gauss();
for (int i=2;i<=n;i++)
ans=ans*a[i][i]%p;
ans=(ans%p+p)%p;
printf("%lld\n",ans);
return 0;
}