1. 程式人生 > >2018.10.28【CQOI2018】【洛谷P4455】【BZOJ5297】社交網路(有向圖矩陣樹)

2018.10.28【CQOI2018】【洛谷P4455】【BZOJ5297】社交網路(有向圖矩陣樹)

洛谷傳送門

解析:

其實KirchoffKirchoff的無向圖矩陣本來就是有向圖矩陣的一個擴充套件。所以這裡僅將有向圖的KirchoffKirchoff矩陣作一個簡單的闡述,詳細證明請參考其他dalaodalao的部落格。(才不是因為我看網上證明都這麼多了懶得寫呢)

一條有向邊<u,v><u,v>KirchoffKirchoff矩陣上我們將Cv,vC_{v,v}加1,因為這是入度,並且在Cv,uC_{v,u}上減一。

最後我們要計算的是以某個節點為根的樹形圖的個數,我們將這個節點編號的一行一列去掉,計算剩餘部分的行列式就行了。

其實會了這道題再回去看無向圖的MatrixTreeMatrix Tree定理就覺得一切都明白了許多。

所以這裡為了方便,將所有節點編號-1,算出矩陣去掉第0行再計算行列式就行了。

由於是求模意義下的,所以要採用歐幾里得迭代法來實現高斯消元,將原矩陣消成上三角矩陣。

程式碼:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc getchar
#define pc putchar
#define cs const

inline
int getint(){ re int num; re char c; while(!isdigit(c=gc()));num=c^48; while(isdigit(c=gc()))num=(num<<1)+(num<<3)+(c^48); return num; } cs int mod=10007,N=251; struct matrix{ int arr[N][N]; int *cs operator[](cs int &offset){ return arr[offset]; } int matrix_tree(int n){
for(int re i=1;i<=n;++i) for(int re j=1;j<=n;++j)arr[i][j]=(arr[i][j]%mod+mod)%mod; int res=1; for(int re i=1;i<=n;++i){ for(int re j=i+1;j<=n;++j){ while(arr[j][i]){ int tmp=arr[i][i]/arr[j][i]; for(int re k=i;k<=n;++k)arr[i][k]=(arr[i][k]-arr[j][k]*tmp%mod+mod)%mod; for(int re k=i;k<=n;++k)swap(arr[i][k],arr[j][k]); res=mod-res; } } res=(res*arr[i][i])%mod; } return res; } }C; int n,m; signed main(){ n=getint(); m=getint(); for(int re i=1;i<=m;++i){ int v=getint()-1; int u=getint()-1; ++C[v][v]; --C[v][u]; } cout<<C.matrix_tree(n-1); return 0; }