上面是矩阵树的知识点,证明有兴趣可以百度,我感觉不想看的话直接当定理记住就行(就像勾股定理,谁管他咋证明的,用就完事了)
构造出矩阵K后,生成树个数就是:矩阵K的n-1阶主子式的值。
可以把矩阵变为上三角矩阵,下三角值均为0.这样矩阵行列式的值就是对角线的乘积。
而由于这题模数不为质数,所以我们不能用高斯消元的做法直接消去。
但我们的目的只是把下三角清零,所以可以用辗转相除的方法来消去下三角。
具体实现看代码即可:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define re register
const int mod=1e9;
const int M = 1e5+7;
ll a[110][110];char s[20][20];
int n,m;
map<pair<int,int>,int>mp;
void add(int u,int v)
{
// cout<<u<<" - - "<<v<<endl;
a[u][u]++;a[v][v]++;
a[u][v]--;a[v][u]--;
}
ll qpow(ll a,ll b)
{
ll ans=1;
while(b)
{
if(b&1)ans=ans*a%mod;
a=a*a%mod;
b>>=1;
}
return ans;
}
ll gao(int n)//求前n-1主子式 的值
{
ll ans=1;
for(int j=1;j<n;j++)//枚举列
for(int i=j+1;i<n;i++)//枚举待变0 的行
while(a[i][j])
{
ll d=a[j][j]/a[i][j];//辗转相除法
for(int k=j;k<n;k++)a[j][k]=(a[j][k]-a[i][k]*d%mod+mod)%mod,swap(a[i][k],a[j][k]);
ans*=-1;//交换任意两行,行列式的值取相反数
}
for(int i=1;i<=n-1;i++)ans=ans*a[i][i]%mod;
return (ans+mod)%mod;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)scanf("%s",(s[i]+1));
int sz=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
if(s[i][j]=='*')continue;
mp[{i,j}]=++sz;
if(s[i-1][j]=='.')add(sz,mp[{i-1,j}]);
if(s[i][j-1]=='.')add(sz,mp[{i,j-1}]);
}
printf("%lld\n",gao(sz)%mod);
return 0;
}