矩陣樹定理 生成樹計數 學習筆記

2021-10-08 22:36:54 字數 3760 閱讀 4873

對於乙個圖g

gg,定義其度數矩陣為d(g

)d(g)

d(g)

.d (g

)d(g)

d(g)

是乙個n∗n

n*nn∗

n大小的對角線矩陣.

對角線上元素d(i

,i)d_

d(i,i)

​為頂點i

ii的度數。(非對角線上的元素d(i

,j)d_

d(i,j)

​為0)

對於乙個圖g

gg,定義其臨接矩陣為a(g

)a(g)

a(g).a(i

,j)a_

a(i,j)

​為vi

v_ivi

​和vj

v_jvj

​之間鄰接的邊數(注意可以有重邊,即大於1)

k ir

chof

f為乙個

n∗n的

矩陣

kirchoff為乙個n*n的矩陣

kircho

ff為一

個n∗n

的矩陣:d(g

)−a(

g)

d(g)-a(g)

d(g)−a

(g)即對於∀i,

j,ki

,j=d

i,j−

ai,j

∀i,j,k_=d_-a_

∀i,j,k

i,j​

=di,

j​−a

i,j​

定理:對於乙個圖g

gg,其生成樹個數為該kirchoff矩陣行列式的值。

證明略過,會用即可。

用高斯消元法即可求得行列式的值。

模板如下(借用了洛谷某位大佬的):

void add

(int u,

int v)

ll gauss

(int n)

} ans=

1ll*ans*a[i]

[i]%mod,ans=

(ans+mod)

%mod;

}return ans;

}

注意呼叫gauss函式時傳入的是n-1.

例題傳送門:

第一題附上這位大佬的**(我比較懶就沒敲了):

大佬傳送門

#include 

#include

const

int n=

15,m=

105;

const

int mod=

1e9;

char s[n]

[n];

int n,m,a[m]

[m],id[n]

[n];

void add

(int u,

int v)

intgauss

(int n)

} ans=

1ll*ans*a[i]

[i]%mod,ans=

(ans+mod)

%mod;

}return ans;

}int

main()

printf

("%d\n"

,gauss

(idx-1)

);return0;

}

第二題

對於二進位制每一位拆位計算貢獻即可。

#include .h>

using namespace std;

#define maxn 300050

#define ll long long

const

int n=

105,m=

105;

const ll mod=

998244353

;int n,m;

ll a[n]

[n];

ll qpow

(ll x,ll y)

return res;

}ll inv

(ll x)

void add

(int u,

int v)

ll gauss

(int n)

} ans=

1ll*ans*a[i]

[i]%mod,ans=

(ans+mod)

%mod;

}return ans;

}int d[n]

[n][32]

;int

main()

add(u,v);}

ll all=

gauss

(n-1);

ll ans=0;

for(

int j=

0;j<

30;j++)}

ans+=

(1ll<*gauss

(n-1

)%mod;

ans%=mod;

} ans=ans*

inv(all)

%mod;

cout<}}

第三題

容斥即可,建議自己手寫關於這個組合數的式子證明一下結論的正確性:

a ns

=∑i=

1n(−

1)i−

1f(n

+1−i

)ans=\sum_^(-1)^f(n+1-i)

ans=∑i

=1n​

(−1)

i−1f

(n+1

−i)f(i

)f(i)

f(i)

表示最多i

ii個公司參與修建的生成樹個數.

#include .h>

using namespace std;

const

int n=

18,m=18;

const long long mod=

1e9+7;

#define ll long long

ll n,a[m]

[m],id[n]

[n];

int m[n]

;int v[n]

[n*n][2

];inline void add

(int u,

int v)

int d[30]

;inline int

gauss

(int n)

} ans=

1ll*ans*a[i]

[i]%mod,ans=

(ans+mod)

%mod;

}return ans;

}int

main()

}int all=

1<<

(n);

long long ans=0;

for(register int i=

1;i++i)}}

if((n-cnt)&1

) ans=

(ans-

gauss

(n)+mod)

%mod;

else

ans=

(ans+

gauss

(n))

%mod;

} cout<}

學習筆記 生成樹計數 矩陣樹定理

問題描述 給定n階無向圖求其生成樹個數。引入 行列式 乙個n n的矩陣a的行列式det a 或者 a 定義為 p p n 1 f p ni 1ai pi p p n 1 f p i 1 nai,pi 其中p n 表示長度為n的排列的集合,f p 表示排列p的逆序對個數。行列式具有以下性質 1.a a...

學習筆記 矩陣樹定理

因為在臨時抱佛腳,所以是沒有證明的 對於行列式 d 任意第 i 行 列同理 按下式展開的值與行列式值相等 text sum n 1 cdot a cdot m 其中 m 是 a 的余子式。一些閒話 這個可以用來推導 輪狀病毒 一題中的遞推式。構造連通矩陣和度數矩陣。連通矩陣 a 的第 i 行第 j ...

BZOJ 1016 最小生成樹計數(矩陣樹定理)

我們把邊從小到大排序,然後依次插入一種權值的邊,然後把每乙個聯通塊合併。然後當一次插入的邊不止一條時做矩陣樹定理就行了。算出有多少種生成樹就行了。剩下的交給乘法原理。實現一不小心就會讓程式變得很醜 include include include include includeusing namesp...