BZOJ 4031: [HEOI2015]小Z的房间 Matrix-Tree定理
题目链接:
http://www.lydsy.com/JudgeOnline/problem.php?id=4031
题解:
Matrix-tree定理解决生成树计数问题,其中用到高斯消元法求上三角矩阵,其中消元用的是辗转相除法。
代码:
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int mod = 1e9; const int maxn = 111; typedef long long LL; int n, m, tot; char str[maxn][maxn]; int mp[maxn][maxn]; LL C[maxn][maxn]; const int dx[] = { 0,0,-1,1 }; const int dy[] = { -1,1,0,0 }; LL Det(int n) { LL ret = 1; int f = 1; for (int i = 1; i <= n; i++) { for (int j = 1; j <= n; j++) { C[i][j] = (C[i][j] % mod + mod) % mod; } } for (int i = 1; i <= n; i++) { for (int j = i + 1; j <= n; j++) { int A = C[i][i], B = C[j][i]; while (B!=0) { LL t = A / B; A = A%B; swap(A, B); for (int k = i; k <= n; k++) { C[i][k] = (C[i][k] - t*C[j][k] % mod + mod) % mod; } for (int k = i; k <= n;k++) { swap(C[i][k], C[j][k]); } f = -f; } } ret = ret*C[i][i] % mod; } if (f == -1) ret = ((-ret)%mod + mod) % mod; return ret; } void init() { tot = 0; memset(C, 0, sizeof(C)); } int main() { while (scanf("%d%d", &n, &m) == 2 && n) { init(); for (int i = 0; i < n; i++) scanf("%s", str[i]); for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { if (str[i][j] == '.') { mp[i][j] = ++tot; } } } for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { if (str[i][j] == '.') { for (int t = 0; t < 4; t++) { int ii = i + dx[t], jj = j + dy[t]; if (ii < 0 || ii >= n || jj < 0 || jj >= m || str[ii][jj] == '*') continue; C[mp[i][j]][mp[i][j]]++; C[mp[i][j]][mp[ii][jj]]--; } } } } LL ans=Det(tot - 1); printf("%lld\n", ans); } return 0; }