P4111 [HEOI2015]小Z的房间

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;
}

 

posted @ 2018-09-17 22:10  kafuuchino  阅读(143)  评论(0编辑  收藏  举报