Matrix-Tree定理(2)----矩阵树定理

xiaoxiao2021-02-28  126

那么,现在就可以进入正题了-------->矩阵树定理(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 <bits/stdc++.h> #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; }

转载请注明原文地址: https://www.6miu.com/read-27426.html

最新回复(0)