关于生成树计数,有一个叫matrix-tree定理的东西.可以参考《生成树的计数及其应
用》.
主要就是把原图用一个 Kirchhoff矩阵存下来,这个矩阵是原图的关联矩阵和自身的
转置的乘积,简单处理就是对角线表示这个节点的度数,然后矩阵中其他元素如果存
在这条边就是-1,否则就是0.
然后这个图的生成树个数就是Kirchhoff矩阵任意n-1阶主子式的行列式值.
UVA 10766:点击打开链接
题意是给定m条边,求反图的生成树个数,k是没用的.
对反图建立Kirchhoff矩阵,然后直接求n-1阶主子式的值就好了.
坑点是要用long double,还有注意重边处理.
#include <cstdio> #include <cstring> #include <algorithm> #include <iostream> #include <vector> #include <queue> #include <cmath> using namespace std; #define maxn 55 int n, m, k; bool mp[maxn][maxn]; int degree[maxn]; #define eps 1e-10 long double a[maxn][maxn]; long long det () { long double ans = 1.0; int i, j, k, col, max_r; for (k = 0, col = 0; k < n && col < n; k++, col++) {//转化成上三角矩阵 max_r = k; for (int i = k+1; i < n; i++) { //找到最大的绝对值数所在的行 if (fabs (a[i][col]) > fabs (a[max_r][col])) max_r = i; } if (fabs (a[max_r][col]) <= eps) return 0; if (k != max_r) { //交换行 for (int j = col; j < n; j++) { swap (a[k][j], a[max_r][j]); } ans *= (-1);//行列式换行改变符号 } for (int i = k+1; i < n; i++) { //消去 if (a[i][col]) { long double tmp = -a[i][col]/a[k][col]; for (int j = col; j < n; j++) { a[i][j] += tmp*a[k][j]; } } } } for (i = 0; i < n; i++) ans *= a[i][i]; long long p1 = ceil (ans), p2 = floor (ans); if (ans-p2 < p1-ans) return p2; else return p1; } int main () { //freopen ("in.txt", "r", stdin); while (cin >> n >> m >> k) { memset (mp, 0, sizeof mp); memset (degree, 0, sizeof degree); for (int i = 0; i < m; i++) { int u, v; cin >> u >> v; if (!mp[u][v]) degree[u]++, degree[v]++; mp[u][v] = mp[v][u] = 1; } for (int i = 1; i <= n; i++) degree[i] = n-1-degree[i]; for (int i = 1; i <= n; i++) { for (int j = 1; j <= n; j++) { if (i == j) { a[i-1][j-1] = degree[i]; } else if (mp[i][j]) { a[i-1][j-1] = 0; } else a[i-1][j-1] = -1; } } n--; long long ans = det (); cout << ans << "\n"; } return 0; }