BZOJ4031: [HEOI2015]小Z的房间
n,m<=9,n*m的网格图,相邻的.可连边,问把所有的.连成一棵树有多少方案,%1e9。
直接矩阵树,然而高斯消元时模数不是质数没法直接除,所以利用行列式的性质,某一行乘某个数加到另一行上,这样辗转相除。
1 #include<stdio.h> 2 #include<string.h> 3 #include<algorithm> 4 #include<stdlib.h> 5 //#include<queue> 6 #include<math.h> 7 //#include<time.h> 8 //#include<iostream> 9 using namespace std; 10 11 int n,m,tot=0; 12 char mp[13][13]; 13 int mat[111][111],who[111][111]; 14 const int mod=1e9; 15 16 int gauss(int n) 17 { 18 for (int i=1;i<=n;i++) 19 for (int j=1;j<=n;j++) 20 mat[i][j]+=mat[i][j]<0?mod:0; 21 int ans=1; 22 for (int i=1;i<=n;i++) 23 for (int j=i+1;j<=n;j++) 24 { 25 int A=mat[i][i],B=mat[j][i]; 26 while (B) 27 { 28 int t=A/B; A%=B; swap(A,B); 29 for (int k=i;k<=n;k++) 30 mat[i][k]-=1ll*mat[j][k]*t%mod, 31 mat[i][k]+=mat[i][k]<0?mod:0; 32 for (int k=i;k<=n;k++) {int t=mat[j][k]; mat[j][k]=mat[i][k]; mat[i][k]=t;} 33 ans=ans==1?mod-1:1; 34 } 35 } 36 for (int i=1;i<=n;i++) ans=1ll*ans*mat[i][i]%mod; 37 return ans; 38 } 39 40 int main() 41 { 42 scanf("%d%d",&n,&m); 43 for (int i=1;i<=n;i++) scanf("%s",mp[i]+1); 44 for (int i=1;i<=n;i++) 45 for (int j=1;j<=m;j++) 46 if (mp[i][j]=='.') who[i][j]=++tot; 47 for (int i=1;i<=n;i++) 48 for (int j=1;j<=m;j++) 49 if (mp[i][j]=='.') 50 { 51 if (mp[i+1][j]=='.') mat[who[i][j]][who[i+1][j]]--,mat[who[i][j]][who[i][j]]++; 52 if (mp[i][j+1]=='.') mat[who[i][j]][who[i][j+1]]--,mat[who[i][j]][who[i][j]]++; 53 if (mp[i-1][j]=='.') mat[who[i][j]][who[i-1][j]]--,mat[who[i][j]][who[i][j]]++; 54 if (mp[i][j-1]=='.') mat[who[i][j]][who[i][j-1]]--,mat[who[i][j]][who[i][j]]++; 55 } 56 printf("%d\n",gauss(tot-1)); 57 return 0; 58 }