生成树计数问题(SPOJ 104 Highways)
周冬的《生成树的计数及其应用》论文上讲到过生成树计数的问题。
用到的是一个Kirchhoff矩阵,它是这样定义的:
a、设一个度数矩阵D,当i == j时,Dij = (i这个节点的度数),否则Dij = 0;
b、设一个连通性矩阵A,如果i 和j连通,则Aij等于i到j的边数,否则Aij等于0;
Kirchhoff矩阵C = D - A;
有了Kirchhoff矩阵这个工具,我们可以引入Matrix-Tree定理:
对于一个无向图G,它的生成树个数等于其Kirchhoff矩阵任何一个n-1阶主子式的行列式的绝对值(可以用高斯消元解,线性代数没学好的面壁去。。。-_-!)。
所谓n-1阶主子式,就是对于任意一个r,将C的第r行和第r列同时删去后的新矩阵,用Cr表示。
代码(SPOJ 104 Highways)
View Code
//#pragma comment(linker,"/STACK:327680000,327680000") #include <iostream> #include <cstdio> #include <cmath> #include <vector> #include <cstring> #include <algorithm> #include <string> #include <set> #include <functional> #include <numeric> #include <sstream> #include <stack> #include <map> #include <queue> #define CL(arr, val) memset(arr, val, sizeof(arr)) #define REP(i, n)for((i) = 0; (i) < (n); ++(i)) #define FOR(i, l, h)for((i) = (l); (i) <= (h); ++(i)) #define FORD(i, h, l)for((i) = (h); (i) >= (l); --(i)) #define L(x)(x) << 1 #define R(x)(x) << 1 | 1 #define MID(l, r)(l + r) >> 1 #define Min(x, y)x < y ? x : y #define Max(x, y)x < y ? y : x #define E(x)(1 << (x)) #define iabs(x) (x) < 0 ? -(x) : (x) #define OUT(x)printf("%I64d\n", x) #define lowbit(x)(x)&(-x) #define Read()freopen("data.in", "r", stdin) #define Write()freopen("data.out", "w", stdout); const double eps = 1e-8; typedef long long LL; const int inf = ~0u>>2; using namespace std; const int N = 111; const int M = 2111; const int MOD = 31011; int b[N]; bool zero(double x) { return x > -eps && x < eps; } double det(double mat[N][N], int n) { double mul, res = 1; int i, j, k; for(i = 0; i < n; ++i) b[i] = i; for(i = 0; i < n; ++i) { if(zero(mat[b[i]][i])) { for(j = i + 1; j < n; ++j) { if(!zero(mat[b[j]][i])) {swap(b[i], b[j]); res *= -1; break;} } } res *= mat[b[i]][i]; for(j = i + 1; j < n; ++j) { if(!zero(mat[b[j]][i])) { mul = mat[b[j]][i]/mat[b[i]][i]; for(k = i; k < n; ++k) { mat[b[j]][k] -= mat[b[i]][k]*mul; } } } } return res; } int D[N][N], A[N][N]; double G[N][N]; int main() { //freopen("data.in", "r", stdin); int T, i, j; int n, m, x, y; cin >> T; while(T--) { scanf("%d%d", &n, &m); CL(D, 0); CL(A, 0); while(m--) { scanf("%d%d", &x, &y); A[x-1][y-1] = A[y-1][x-1] = 1; } for(i = 0; i < n; ++i) { x = 0; for(j = 0; j < n; ++j) { if(A[i][j]) {x++;} } D[i][i] = x; } for(i = 0; i < n; ++i) { for(j = 0; j < n; ++j) G[i][j] = D[i][j] - A[i][j]; } printf("%.0f\n", det(G, n-1)); } return 0; }