P4111 HEOI2015 小Z的房間

2022-05-20 01:51:57 字數 1652 閱讀 4888

傳送門

轉換題意後就是問你生成樹的方案數

就是裸的矩陣樹定理

不會證明,只懂結論:

對於乙個無向圖 g

定義g的度數矩陣 d[g] 是乙個 n*n 的矩陣,並且滿足:當  i ≠ j  時,d[i][j] = 0,當 i = j 時,d[i][j]等於 vi 的度數

定義g的鄰接矩陣 a[g] 是乙個 n*n 的矩陣,並且滿足:如果 vi,vj 之間有邊直接相連,則 a[i][j] = 1 否則為 0

定義g的 kirchhoff 矩陣 c[g] 為 c[g] = d[g] - a[g],則 matrix-tree定理可描述為:

g的所有不同的生成樹的個數等於其 kirchhoff 矩陣 c[g] 的任何乙個 n-1 階主子式的行列式的絕對值。

n-1 階主子式就是將 c[g] 的第 r 行,第 r 列同時去掉後得到的的新矩陣(1 ≤ r ≤ n),用cr[g]表示

行列式是什麼不需要知道,

只要知道怎麼求

有下面的結論:

1.交換兩行/列位置,行列式的值取相反數

2.用一行的倍數減去另一行,行列式的值不變

3.乙個上三角行列式的值等於對角線的乘積

然後只要考慮如何把cr[g]搞成上三角形式的矩陣

考慮高斯消元時的做法,把cr[g]也用同樣的方法搞成上三角形式

因為消元時有除法,而剩餘系下沒有除法,所以要用輾轉相除法:

設當前位置值為 a ,然後我們要消掉另一行的 b

那麼把 b 整行減去 (a 整行 * [b/a] )    [b/a]表示 b除a下取整

那麼 (a,b) --> (a,b%a)

然後交換兩行繼續操作直到有乙個為 0

注意每次交換後ans都要取相反數

計算矩陣行列式的**如下:

//ans初始為1,a是矩陣

for(int j=1;j<=cnt;j++)

ans=ans*a[j][j]%mo;

}

附上完整**:

#include#include

#include

#include

#include

using

namespace

std;

const

int mo=1e9;

intn,m;

char mp[17][17

];int a[107][107],a[17][17],cnt;//

矩陣a就是cr[g]

long

long ans=1

;void

slove()

ans=ans*a[j][j]%mo;

}ans=(ans+mo)%mo;

}int

main()

//處理矩陣a

for(int i=1;i<=cnt;i++)

for(int j=1;j<=cnt;j++)

if(a[i][j]&&i!=j) a[i][i]++;//

處理矩陣a

slove();

printf(

"%lld

",ans);

return0;

}

P4111 HEOI2015 小Z的房間

你的房子可以看做是乙個包含n m個格仔的格狀矩形,每個格仔是乙個房間或者是乙個柱子。在一開始的時候,相鄰的格仔之間都有牆隔著。你想要打通一些相鄰房間的牆,使得所有房間能夠互相到達。在此過程中,你不能把房子給打穿,或者打通柱子 以及柱子旁邊的牆 同時,你不希望在房子中有小偷的時候會很難抓,所以你希望任...

HEOI2015 小Z的房間

其實是矩陣樹定理模板題。但是要注意不合法的情況預處理的時候設定成0,要不然計算行列式的時候有問題。直接跳過不合法情況,不給它建立新點就行了。如下 include include include include define mod 1000000000 using namespace std int...

HEOI2015 BZOJ4031 小Z的房間

description 你突然有了乙個大房子,房子裡面有一些房間。事實上,你的房子可以看做是乙個包含n m個格仔的格狀矩形,每個格仔是乙個房間或者是乙個柱子。在一開始的時候,相鄰的格仔之間都有牆隔著。你想要打通一些相鄰房間的牆,使得所有房間能夠互相到達。在此過程中,你不能把房子給打穿,或者打通柱子 ...