那么,现在就可以进入正题了-------->矩阵树定理(Matrix Tree Theorem)
不知道矩阵行列式等线性代数知识的,请左转:点击打开链接
Part 1 Matrix Tree定理
引入几个概念:
一个图的邻接矩阵G:对于无向图的边(u,v),G[u][v]++,G[v][u]++
一个图的度数矩阵D:对于无向图的边(u,v),D[u][u]++,D[v][v]++;
而通过这两个矩阵就可以构造出图G的基尔霍夫矩阵:C=D-G.
Matrix Tree定理:将图G的基尔霍夫矩阵去掉第i行和第i列(i可以取任意值,可以证明所得到的结果相同),得到(n-1)*(n-1)的矩阵,
对这个矩阵进行行列式的值求解,abs(det(A))即为图G的生成树个数。
求解矩阵行列式的时候,计算常数k时为了避免精度丢失,可以通过计算逆元进行求解(不需要取模时,mod一个大质数即可).
下面给一道MatrixTree定理裸题:SPOJ P104 Highways
Part 2 Matrix Tree定理在有向图上的拓展
Matrix Tree定理的拓展与延伸------有向图的Matrix Tree定理
对于有向图G,不存在生成树的概念,但存在树形图的概念。
树形图:以i点为根节点的树形图有(n-1)条边,从i节点出发可以到达其他所有(n-1)个节点.
定义: 有向图的邻接矩阵G:对于有向图的边(u,v),G[u][v]++.
有向图的度数矩阵D:对于有向图的边(u,v),D[v][v]++.
尤其需要注意的是:有向图的度数矩阵指的是一个点的入度,而不是出度。
而有向图的基尔霍夫矩阵的构造方式是一模一样的:C=D-G.
有向图Matrix Tree定理:
将有向图G的基尔霍夫矩阵去掉第i行和第i列,得到(n-1)*(n-1)的矩阵,
对这个矩阵进行行列式的值求解,abs(det(A))就是以i为根的树形图的个数。
最后,来看一道例题:
给一个图G,边带权,定义X树形图为以n号节点为根的树形图的个数,此处树形图定义为有n个点,n-1条边,所有节点都能够到达根节点的图,
求所有X树形图的权值之和,答案mod 1e9+7 。数据范围:n<=50,m<=200
题解:
这道题的树形图定义不太一样,但稍加分析可知,
将边反向,即可转化为以n为根的普通树形图。
接下来,先用上述的定理O(n^3)求出所有符合条件的树形图个数T,
考虑每条边对于答案的贡献:
把第i条边从图G中删除,再求符合条件的树形图个数T’,
这样,T-T’即为这条边所在的树形图个数,
乘以权值后累加即可求得答案。
时间复杂度:O(m*n^3).
这道题通过线性代数技巧优化求行列式的复杂度,
可以做到O(n^3+nm),这里就不说了.
<其实是博主太弱,不会>
Code:
#include
#define ll long long
#define mod 1000000007ll
using namespace std;
int u[205],v[205];
ll w[205],a[55][55],c[55][55];
int n,m;
inline ll qpow(ll a,ll b)
{ll res=1ll,tp=a;
while (b)
{if (b&1ll) {res*=tp;res%=mod;}
tp*=tp;tp%=mod;b>>=1ll;
}
return res;
}
inline ll det()
{//计算矩阵C的(n-1)阶主子式的行列式的值
int i,j,k;
for (i=1;i<=n-1;i++)
{for (j=i+1;j<=n-1;j++)
{//c[j][i]-p*c[i][i]=0
ll p=(c[j][i]*qpow(c[i][i],mod-2ll))%mod;
for (k=i;k<=n-1;k++)
{c[j][k]-=p*c[i][k];c[j][k]%=mod;
if (c[j][k]<0) {c[j][k]+=mod;}
}
}
}
ll ret=1;
for (i=1;i<=n-1;i++)
{ret*=c[i][i];ret%=mod;}
return ret;
}
int main (){
int i;
scanf ("%d%d",&n,&m);
for (i=1;i<=m;i++)
{scanf ("%d%d%lld",&u[i],&v[i],&w[i]);
c[v[i]][u[i]]--;c[u[i]][u[i]]++;
}
memcpy(a,c,sizeof(c));
ll t1=det(),ans=0;
for (i=1;i<=m;i++)
{memcpy(c,a,sizeof(a));
c[v[i]][u[i]]++;c[u[i]][u[i]]--;
ll t2=(t1-det()+mod)%mod;
t2*=w[i];t2%=mod;
ans+=t2;ans%=mod;
}
printf ("%lld\n",ans);
return 0;
}