一、题目
二、解法
本题就是矩阵树定理中外向树的情况。
矩阵树定理原来求的是生成树的数量,但是这里要求生成树边权乘积之和,观察行列式的定理,不难发现矩阵构建时换成边权就行了。
有两个结论:
- 外向树的度数矩阵是到该点的入边权值总和;内向树的度数矩阵是到该点的出边权值总和
- 如果需要指定 i i i为根,那么就删除 i i i行 i i i列的再求行列式即可
原理作者没有搞太懂,中考完了再深究吧。
#include <cstdio>
#include <iostream>
using namespace std;
#define int long long
const int M = 305;
const int MOD = 1e9+7;
int read()
{
int num=0,flag=1;
char c;
while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
while(c>='0'&&c<='9')num=(num<<3)+(num<<1)+(c^48),c=getchar();
return num*flag;
}
int n,m,t,a[M][M],ans=1;
int qkpow(int a,int b)
{
int r=1;
while(b>0)
{
if(b&1) r=r*a%MOD;
a=a*a%MOD;
b>>=1;
}
return r;
}
void guass()
{
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;
}
int inv=qkpow(a[i][i],MOD-2);
for(int j=i+1;j<=n;j++)
{
int tmp=a[j][i]*inv%MOD;
//高斯消元的经典错误,一定要提前算出来
for(int k=i;k<=n;k++)
a[j][k]=(a[j][k]-a[i][k]*tmp%MOD)%MOD;
}
}
}
signed main()
{
n=read();m=read();t=read();
for(int i=1;i<=m;i++)
{
int u=read(),v=read(),c=read();
if(t==0)
{
a[u][u]=(a[u][u]+c)%MOD;a[v][v]=(a[v][v]+c)%MOD;
a[u][v]=(a[u][v]-c)%MOD;a[v][u]=(a[v][u]-c)%MOD;
}
else
{
a[v][v]=(a[v][v]+c)%MOD;a[u][v]=(a[u][v]-c)%MOD;
}
}
guass();
for(int i=2;i<=n;i++) ans=ans*a[i][i]%MOD;
printf("%lld\n",(ans%MOD+MOD)%MOD);
}