傳送門
轉換題意後就是問你生成樹的方案數
就是裸的矩陣樹定理
不會證明,只懂結論:
對於乙個無向圖 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個格仔的格狀矩形,每個格仔是乙個房間或者是乙個柱子。在一開始的時候,相鄰的格仔之間都有牆隔著。你想要打通一些相鄰房間的牆,使得所有房間能夠互相到達。在此過程中,你不能把房子給打穿,或者打通柱子 ...