p4111 [HEOI2015]小Z的房间[简述矩阵树定理]
分析
[1]无向图
图G的度数矩阵为D,邻接矩阵为A
我们定义这个图的Kirchhoff矩阵为D-A
这个矩阵的任意一个n-1阶主子式的行列式的绝对值就是这个图的生成树个数
[2]有向图
如果要求内向树计数,矩阵是 出度矩阵-邻接矩阵
如果要求外向树计数,矩阵是 入度矩阵-邻接矩阵
注意有向树计数的时候,删除一行一列,必须删除根所在的行列。
对于这个题我们只需要将一个点与周围的非障碍点连边
然后求无向图的生成树个数即可
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cctype>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<ctime>
#include<vector>
#include<set>
#include<map>
#include<stack>
using namespace std;
const int mod = 1e9;
const int dx[] = {0,0,1,-1};
const int dy[] = {1,-1,0,0};
int n,m,g[110][110],wh[110][110],cnt;
char s[110][110];
inline int gs(){
int i,j,k,ans=1;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
g[i][j]=(g[i][j]%mod+mod)%mod;
for(i=1;i<=n;i++){
for(j=i;j<=n;j++)
if(g[i][j])break;
if(j>n)return 0;
if(j!=i)ans=mod-ans,swap(g[i],g[j]);
for(j=i+1;j<=n;j++){
while(g[j][i]){
int t=g[i][i]/g[j][i];
for(k=i;k<=n;k++)
g[i][k]=(g[i][k]-1ll*t*g[j][k]%mod+mod)%mod;
swap(g[i],g[j]);
ans=mod-ans;
}
}
ans=1ll*ans*g[i][i]%mod;
}
return ans;
}
int main(){
int i,j,k;
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++){
scanf("%s",s[i]+1);
for(j=1;j<=m;j++)
if(s[i][j]=='.')
wh[i][j]=++cnt;
}
for(i=1;i<=n;i++)
for(j=1;j<=m;j++){
if(!wh[i][j])continue;
for(k=0;k<4;k++)
if(wh[i+dx[k]][j+dy[k]]){
int id=wh[i][j];
g[id][id]++;
g[id][wh[i+dx[k]][j+dy[k]]]--;
}
}
n=cnt-1;
printf("%d\n",gs());
return 0;
}