P4111 [HEOI2015]小Z的房间(矩阵树)
题目描述
你突然有了一个大房子,房子里面有一些房间。事实上,你的房子可以看做是一个包含n*m个格子的格状矩形,每个格子是一个房间或者是一个柱子。在一开始的时候,相邻的格子之间都有墙隔着。
你想要打通一些相邻房间的墙,使得所有房间能够互相到达。在此过程中,你不能把房子给打穿,或者打通柱子(以及柱子旁边的墙)。同时,你不希望在房子中有小偷的时候会很难抓,所以你希望任意两个房间之间都只有一条通路。现在,你希望统计一共有多少种可行的方案。
输入输出格式
输入格式:第一行两个数分别表示n和m。
接下来n行,每行m个字符,每个字符都会是’.’或者’*’,其中’.’代表房间,’*’代表柱子。
输出格式:一行一个整数,表示合法的方案数 Mod 10^9
输入输出样例
说明
对于前20%的数据,n,m <= 3
对于前50%的数据,n,m <=5
对于前100%的数据,n,m<=9
有40%的数据保证,min(n,m)<=3
有30%的数据保证,不存在柱子
无向图
A = 度数矩阵 - 邻接矩阵
板子不解释 QWQ
1 #include<iostream>
2 #include<cstdio>
3 #include<algorithm>
4 #include<cstring>
5 #include<cmath>
6 #include<queue>
7 #include<map>
8 #include<set>
9 #define mk make_pair
10 #define ll long long
11 #define int long long
12 using namespace std;
13 inline int read()
14 {
15 int x=0,f=1;char ch=getchar();
16 while (!isdigit(ch)) {if (ch=='-') f=-1;ch=getchar();}
17 while (isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
18 return x*f;
19 }
20 const int maxn = 210;
21 const int mod = 1e9;
22 int a[maxn][maxn];
23 int n,m;
24 int d[maxn];
25 char s[maxn][maxn];
26 int num[maxn][maxn];
27 int cnt;
28 int dx[5]={0,1,0,-1,0};
29 int dy[5]={0,0,1,0,-1};
30 int ans=1;
31 int gauss()
32 {
33 int ff=1;
34 for (int i=1;i<=n;i++)
35 for (int j=1;j<=n;j++)
36 a[i][j]=(a[i][j]%mod+mod)%mod;
37
38 for (int i=1;i<=n;i++)
39 {
40 for (int j=i+1;j<=n;j++)
41 {
42 while (a[j][i])
43 {
44 int t = a[i][i]/a[j][i];
45 for (int k=i;k<=n;k++) a[i][k]=(a[i][k]-t*a[j][k]%mod+mod)%mod;
46 swap(a[i],a[j]);
47 ff*=(-1);
48 }
49 }
50 ans=ans*a[i][i]%mod;
51 }
52 if (ff==-1) return (mod-ans)%mod;
53 return ans;
54 }
55
56 int Gauss(int n)
57 {
58 int ans=1;
59 int ff=1;
60 for (int i=1;i<=n;i++)
61 for (int j=1;j<=n;j++)
62 a[i][j]=(a[i][j]%mod+mod)%mod;
63
64 for(int i=1;i<=n;i++)
65 {
66 for(int j=i+1;j<=n;j++)
67 {
68 while(a[j][i])
69 {
70 int t=a[i][i]/a[j][i];
71 for(int k=i;k<=n;k++)
72 a[i][k]-=a[j][k]*t,a[i][k]%=mod,a[i][k]+=mod,a[i][k]%=mod;
73 ff*=-1;
74 swap(a[i],a[j]);
75 }
76 }
77 ans *= a[i][i];
78 ans %= mod;
79 }
80
81 ans *= ff;
82 ans%=mod,ans+=mod,ans%=mod;
83 return ans;
84
85
86
87 }
88
89 signed main()
90 {
91 n=read();m=read();
92 for (int i=1;i<=n;i++)
93 scanf("%s",s[i]+1);
94 for (int i=1;i<=n;i++)
95 for (int j=1;j<=m;j++)
96 if (s[i][j]!='*') num[i][j]=++cnt;
97 for (int i=1;i<=n;i++)
98 {
99 for (int j=1;j<=m;j++)
100 {
101 if (s[i][j]=='*') continue;
102 for (int k=1;k<=4;k++)
103 {
104 int x = i+dx[k];
105 int y = j+dy[k];
106 if (x<=0 || y<=0 || x>n || y>m) continue;
107 if (s[x][y]=='*') continue;
108 a[num[i][j]][num[x][y]]=-1;
109 d[num[i][j]]++;
110 }
111 }
112 }
113 for (int i=1;i<=cnt;i++) a[i][i]=d[i];
114 n=cnt;
115 n--;
116 cout<<Gauss( n);
117 return 0;
118 }