[HEOI2015]小 Z 的房间(矩阵树定理,高斯消元+辗转相除)

题意:

在这里插入图片描述

数据范围:n,m<=9

解法:

矩阵树定理模板题

这题答案需要模1e9,而高斯消元的过程中有除法,
因此本题需要用辗转相除法(欧几里得算法),复杂度多一个log

code:

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxm=15;
const int mod=1e9;
char s[maxm][maxm];
int id[maxm][maxm],idx;
int n,m;
int K[105][105];
int ppow(int a,int b,int mod){
    int ans=1%mod;a%=mod;
    while(b){
        if(b&1)ans=ans*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return ans;
}
int guass(int n){
    int ans=1;
    for(int i=1;i<=n;i++){
        for(int j=i+1;j<=n;j++){
            while(K[j][i]){//直到为0
                int t=K[i][i]/K[j][i];//计算第i行对应的数是第j行的几倍
                for(int k=i;k<=n;k++){//一个一个消去并交换数字(消去之后之前的位置变小)
                    K[i][k]=(K[i][k]-t*K[j][k]%mod+mod)%mod;
                    swap(K[i][k],K[j][k]);//交换
                }
                ans=-ans;//交换行,行列式的值取反
            }
        }
        if(!K[i][i])return 0;//生成树数量为0
        ans=(ans*K[i][i]%mod+mod)%mod;//上三角行列式(右上角)的值为对角线乘积
    }
    return ans;
}
void add(int a,int b){
    K[a][a]++;
    K[b][b]++;
    K[a][b]--;
    K[b][a]--;
}
signed main(){
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        scanf("%s",s[i]+1);
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            if(s[i][j]=='.'){
                id[i][j]=++idx;
            }
        }
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            if(id[i][j]&&id[i][j+1]){
                add(id[i][j],id[i][j+1]);
            }
            if(id[i][j]&&id[i+1][j]){
                add(id[i][j],id[i+1][j]);
            }
        }
    }
    int ans=guass(idx-1);
    cout<<ans<<endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_44178736/article/details/107850968
今日推荐