您的位置:首页 > 其它

[bzoj4031][HEOI2015]小Z的房间【矩阵树定理】【高斯消元】

2018-01-27 11:38 441 查看
【题目描述】

Description

你突然有了一个大房子,房子里面有一些房间。事实上,你的房子可以看做是一个包含n*m个格子的格状矩形,每个格子是一个房间或者是一个柱子。在一开始的时候,相邻的格子之间都有墙隔着。
你想要打通一些相邻房间的墙,使得所有房间能够互相到达。在此过程中,你不能把房子给打穿,或者打通柱子(以及柱子旁边的墙)。同时,你不希望在房子中有小偷的时候会很难抓,所以你希望任意两个房间之间都只有一条通路。现在,你希望统计一共有多少种可行的方案。

Input

第一行两个数分别表示n和m。
接下来n行,每行m个字符,每个字符都会是’.’或者’*’,其中’.’代表房间,’*’代表柱子。

Output

 一行一个整数,表示合法的方案数 Mod 10^9

Sample Input

3 3

...

...

.*.

Sample Output

15

HINT

对于前100%的数据,n,m<=9

Source



【题解】

 矩阵树定理模板题。

基尔霍夫矩阵C=度数矩阵-邻接矩阵
基尔霍夫矩阵的任何一个余子式(去掉第i行第i列)的行列式的值为以i为根的生成树的数量。 --我不会证明
行列式有几个性质。
 1.任意两行(列)互换值取相反数。 证明:逆序对变化了1或1+2*k(k为中间的行数)
 2.若存在两行(列)相同或成比例,行列式值为0。 证明:第一行取i,第二行取j与第一行取j,第二行取i互相抵消。
 3.一行加上另一行或加上的数与另一行比例相同,行列式值不变。 证明:把行列式拆开分别求和。
 4.若行列式为上三角矩阵,行列式的值为对角线元素相乘。 证明:其他项至少有一个值为0
因此,求解行列式时,可以先高斯消元成上三角矩阵再求解。
此外,这一题的P不是质数,所以高斯消元时要用辗转相除。

/* --------------
user Vanisher
problem bzoj-4031
----------------*/
# include <bits/stdc++.h>
# define 	ll 		long long
# define 	N 		110
# define 	P 		1000000000
using namespace std;
const ll dx[4]={1,0,-1,0}, dy[4]={0,1,0,-1};
ll A

,ans,n,m,p

,place;
char mp

;
ll read(){
ll tmp=0, fh=1; char ch=getchar();
while (ch<'0'||ch>'9'){if (ch=='-') fh=-1; ch=getchar();}
while (ch>='0'&&ch<='9'){tmp=tmp*10+ch-'0'; ch=getchar();}
return tmp*fh;
}
void build(ll u, ll v){
A[u][u]++; A[v][v]++;
A[u][v]--; A[v][u]--;
}
void guass(ll num){
for (ll i=1; i<=num; i++)
for (ll j=1; j<=num; j++)
A[i][j]=(A[i][j]+P)%P;
for (ll i=1; i<=num; i++){
for (ll j=i+1; j<=num; j++){
while (A[j][i]!=0){
ll t=A[i][i]/A[j][i];
for (ll k=i; k<=num; k++) A[i][k]=((A[i][k]-t*A[j][k])%P+P)%P;
for (ll k=i; k<=num; k++) swap(A[i][k],A[j][k]);
ans=ans*(-1);
}
}
}
}
ll det(ll num){
ans=1;
guass(num-1);
ans=(ans+P)%P;
for (ll i=1; i<num; i++)
ans=ans*A[i][i]%P;
return ans;
}
int main(){
n=read(), m=read();
for (ll i=1; i<=n; i++)
scanf("\n%s",mp[i]+1);
for (ll i=1; i<=n; i++)
for (ll j=1; j<=m; j++)
if (mp[i][j]=='.') p[i][j]=++place;
for (ll i=1; i<=n; i++)
for (ll j=1; j<=m; j++)
for (ll k=0; k<2; k++){
ll tx=i+dx[k], ty=j+dy[k];
if (tx>0&&ty>0&&tx<=n&&ty<=m)
if (mp[i][j]=='.'&&mp[tx][ty]=='.')
build(p[i][j],p[tx][ty]);
}
printf("%lld\n",det(place));
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: