zoukankan      html  css  js  c++  java
  • [bzoj4031][HEOI2015]小Z的房间【矩阵树定理】【高斯消元】

    【题目描述】

    Description

    你突然有了一个大房子,房子里面有一些房间。事实上,你的房子可以看做是一个包含n*m个格子的格状矩形,每个格子是一个房间或者是一个柱子。在一开始的时候,相邻的格子之间都有墙隔着。

    你想要打通一些相邻房间的墙,使得所有房间能够互相到达。在此过程中,你不能把房子给打穿,或者打通柱子(以及柱子旁边的墙)。同时,你不希望在房子中有小偷的时候会很难抓,所以你希望任意两个房间之间都只有一条通路。现在,你希望统计一共有多少种可行的方案。

    Input

    第一行两个数分别表示n和m。

    接下来n行,每行m个字符,每个字符都会是’.’或者’*’,其中’.’代表房间,’*’代表柱子。

    Output

     一行一个整数,表示合法的方案数 Mod 10^9

    Sample Input

    3 3
    ...
    ...
    .*.

    Sample Output

    15

    HINT

    对于前100%的数据,n,m<=9

    Source

    【题解】

     矩阵树定理模板题。

    基尔霍夫矩阵C=度数矩阵-邻接矩阵

    基尔霍夫矩阵的任何一个余子式(去掉第i行第i列)的行列式的值为以i为根的生成树的数量。 --我不会证明

    行列式有几个性质。

     1.任意两行(列)互换值取相反数。 证明:逆序对变化了1或1+2*k(k为中间的行数)

     2.若存在两行(列)相同或成比例,行列式值为0。 证明:第一行取i,第二行取j与第一行取j,第二行取i互相抵消。

     3.一行加上另一行或加上的数与另一行比例相同,行列式值不变。 证明:把行列式拆开分别求和。

     4.若行列式为上三角矩阵,行列式的值为对角线元素相乘。 证明:其他项至少有一个值为0

    因此,求解行列式时,可以先高斯消元成上三角矩阵再求解。

    此外,这一题的P不是质数,所以高斯消元时要用辗转相除。

    /* --------------
        user Vanisher
        problem bzoj-4031 
    ----------------*/
    # include <bits/stdc++.h>
    # define 	ll 		long long
    # define 	N 		110
    # define 	P 		1000000000
    using namespace std;
    const ll dx[4]={1,0,-1,0}, dy[4]={0,1,0,-1};
    ll A[N][N],ans,n,m,p[N][N],place;
    char mp[N][N];
    ll read(){
    	ll tmp=0, fh=1; char ch=getchar();
    	while (ch<'0'||ch>'9'){if (ch=='-') fh=-1; ch=getchar();}
    	while (ch>='0'&&ch<='9'){tmp=tmp*10+ch-'0'; ch=getchar();}
    	return tmp*fh;
    }
    void build(ll u, ll v){
    	A[u][u]++; A[v][v]++; 
    	A[u][v]--; A[v][u]--;
    }
    void guass(ll num){
    	for (ll i=1; i<=num; i++)
    		for (ll j=1; j<=num; j++)
    			A[i][j]=(A[i][j]+P)%P;
    	for (ll i=1; i<=num; i++){
    		for (ll j=i+1; j<=num; j++){
    			while (A[j][i]!=0){
    				ll t=A[i][i]/A[j][i];
    				for (ll k=i; k<=num; k++) A[i][k]=((A[i][k]-t*A[j][k])%P+P)%P;
    				for (ll k=i; k<=num; k++) swap(A[i][k],A[j][k]);
    				ans=ans*(-1);
    			}
    		}
    	}
    } 
    ll det(ll num){
    	ans=1;
    	guass(num-1);
    	ans=(ans+P)%P;
    	for (ll i=1; i<num; i++)
    		ans=ans*A[i][i]%P;
    	return ans;
    }
    int main(){
    	n=read(), m=read();
    	for (ll i=1; i<=n; i++)
    		scanf("
    %s",mp[i]+1);
    	for (ll i=1; i<=n; i++)
    		for (ll j=1; j<=m; j++)
    			if (mp[i][j]=='.') p[i][j]=++place;
    	for (ll i=1; i<=n; i++)
    		for (ll j=1; j<=m; j++)
    			for (ll k=0; k<2; k++){
    				ll tx=i+dx[k], ty=j+dy[k];
    				if (tx>0&&ty>0&&tx<=n&&ty<=m)
    					if (mp[i][j]=='.'&&mp[tx][ty]=='.')
    						build(p[i][j],p[tx][ty]);
    			}
    	printf("%lld
    ",det(place));
    	return 0;
    }
    


  • 相关阅读:
    【Leetcode】23. Merge k Sorted Lists
    【Leetcode】109. Convert Sorted List to Binary Search Tree
    【Leetcode】142.Linked List Cycle II
    【Leetcode】143. Reorder List
    【Leetcode】147. Insertion Sort List
    【Leetcode】86. Partition List
    jenkins 配置安全邮件
    python 发送安全邮件
    phpstorm 同步远程服务器代码
    phpUnit 断言
  • 原文地址:https://www.cnblogs.com/Vanisher/p/9136029.html
Copyright © 2011-2022 走看看