P4111 [HEOI2015]小Z的房间
矩阵树定理 高斯消元
矩阵树定理:一个图的(度数矩阵-邻接矩阵)的行列式的值是图中所有生成树的方案数
求行列式:把行列式去掉任意一行和一列,转成上三角矩阵,矩阵对角线上元素之积即为行列式的值
于是我们可以用高斯消元把另一半消掉,因为模数并不是质数,所以用辗转相除法。
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int mod=1e9; char q[12]; int n,m,cnt; long long ans=1,d[102][102]; bool b[12][12],w[102]; int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;++i){ scanf("%s",q); for(int j=1;j<=m;++j) b[i][j]= q[j-1]=='.' ? 1:0; } for(int i=1;i<=n;++i) for(int j=1;j<=m;++j){ int _it=(i-1)*m+j; //二维坐标映射成编号 if(!b[i][j]) {w[_it]=1; continue;} if(b[i-1][j]) --d[_it][_it-m],++d[_it][_it]; if(b[i][j-1]) --d[_it][_it-1],++d[_it][_it]; if(b[i+1][j]) --d[_it][_it+m],++d[_it][_it]; if(b[i][j+1]) --d[_it][_it+1],++d[_it][_it]; } //度数矩阵-邻接矩阵 cnt=n*m-1; //默认去掉最后一行和最后一列 for(int i=1;i<=cnt;++i){ if(w[i]) continue; //是墙就跳过 for(int j=i+1;j<=cnt;++j){ if(w[j]) continue; while(d[j][i]){ //辗转相除法高斯消元 int t=d[i][i]/d[j][i]; for(int k=i;k<=cnt;++k) d[i][k]=(d[i][k]-t*d[j][k]+mod)%mod; swap(d[i],d[j]),ans=(mod-ans)%mod; } } ans=(ans*d[i][i]+mod)%mod; //对角线之积 } printf("%lld",(ans+mod)%mod); return 0; }