bzoj4031-小Z的房间

题目

给一个(n*m)的矩阵,每个点可能为“.”或“*”,有多少种方法把矩阵中的点全部连接起来,并且每两个点之间只有一条路径。

分析

题目所求的是一个矩阵内的生成树计数。很容易把这个矩阵转化为一个图。现在我们要在这个图上求生成树计数。
这里要用到Matrix-Tree定理。
这个定理的证明十分复杂,但是描述很简单。
假设有(n)个点,我们的矩阵(A)的定义为 :

  • 如果两个点(i)(j)有直接连边,那么(A_{ij})为1,否则为0
  • (A_{ii})为点(i)的度数
    这个矩阵的任意一个(n-1)阶主子式(即去掉任意的第(i)行和第(i)列)的行列式就是生成树的方案数。
    在实现时,我们选择最后一行和最后一列去掉,计算剩下的行列式。当然去掉第2行和第2列,第3行和第3列,答案也是一样的。
    我们称矩阵(A)为kirchhoff矩阵。
    这个矩阵有几个特殊性质,也符合计数:
  • kirchhoff矩阵的行列式为0,因为每行的和都为0
  • 若图不连通,kirchhoff矩阵的任意n-1阶主子式的行列式为0
  • 若图为一棵树,kirchhoff矩阵的任意n-1阶主子式的行列式为1

时间复杂度为:(O(n^3*logn))

代码

#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long giant;
const int maxn=10;
const giant q=1e9;
const int maxm=maxn*maxn;
const int xx[]={-1,0,1,0};
const int yy[]={0,1,0,-1};
char s[maxn][maxn];
giant a[maxm][maxm];
void sw(giant a[],giant b[],int n) {
	for (int i=1;i<=n;++i) swap(a[i],b[i]);
}
int el(giant a[],giant b[],int t,int n) {
	int tf=1;
	if (a[t]>b[t]) sw(a,b,n),tf*=-1;
	while (a[t] && b[t]) {
		giant k=b[t]/a[t];
		for (int i=1;i<=n;++i) (b[i]=b[i]-(a[i]*k)%q+q)%=q;
		if (a[t]>b[t]) sw(a,b,n),tf*=-1;
	}
	if (!a[t]) sw(a,b,n),tf*=-1;
	return tf;
}
giant eliminate(int n) {
	int f=1;
	for (int i=1;i<n;++i) {
		if (a[i][i]==0) {
			for (int j=i+1;j<=n;++j) if (a[j][i]) {
				f*=-1;
				sw(a[i],a[j],n);
				break;
			}	
		}
		for (int j=i+1;j<=n;++j) f*=el(a[i],a[j],i,n);
	}
	giant ret=1;
	for (int i=1;i<=n;++i) ret=(ret*a[i][i]+q)%q;
	return (ret*f+q)%q;
}
int bh[maxn][maxn];
int main() {
	#ifndef ONLINE_JUDGE
		freopen("test.in","r",stdin);
	#endif
	int n,m;
	scanf("%d%d",&n,&m);
	int dx=0;
	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]=='.') bh[i][j]=++dx;
	for (int i=1;i<=n;++i) for (int j=1;j<=m;++j) if (s[i][j]=='.') {
		int idn=bh[i][j];
		for (int k=0;k<4;++k) {
			int x=i+xx[k],y=j+yy[k];	
			if (x<1 || y<1 || x>n || y>m || s[x][y]!='.') continue;
			int id=bh[x][y];
			a[idn][id]=-1;
			a[idn][idn]++;
		}
	}
	giant ans=eliminate(dx-1);
	printf("%lld
",ans);
}
原文地址:https://www.cnblogs.com/owenyu/p/6724730.html