这里不学习其中的原理的正确性,仅仅注重代码的正确性
生成树的计数问题
生成树的计数问题的时间复杂度为指数级别的,因此能够处理的数据范围还是比较小的。
这里对这里的时间复杂度存疑。感觉时间复杂度为\(O(n^3)\)
适用的范围为无向图。
可以是有向图,不过相应的矩阵的值要进行相应的变化
D 度数矩阵表示为每个点的出度
A 邻接矩阵表示为每两个点连接的边数,允许平行边,包括自环
其中构造的矩阵的过程见下面的博客
生成树的计数 Matrix-Tree(矩阵树)定理# 问题
highways注意spoj注册的时候要翻墙
## 题意
统计有多少个生成树
## 题解
运用生成树计数的算法
## AC代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
| #include <map> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; typedef long long ll; const int maxn = 105; const int maxm = 100005; const int INF = 1e9; int degree[maxn]; ll g[maxn][maxn]; int n, m; ll det(ll a[][maxn], int n) { ll ret = 1; for(int i=1; i<n; ++i){ for(int j=i+1; j<n; ++j){ while(a[j][i]){ ll t = a[i][i]/a[j][i]; for(int k=i; k<n; ++k){ a[i][k] = (a[i][k]-a[j][k]*t); } for(int k=i; k<n; ++k){ swap(a[i][k], a[j][k]); } ret = -ret; } } if(a[i][i]==0){ return 0; } ret = ret*a[i][i]; } if(ret<0){ ret = -ret; } return ret; } void solve() { int u, v; memset(degree, 0, sizeof degree ); memset(g, 0, sizeof g ); scanf("%d%d", &n, &m); while(m--){ scanf("%d%d", &u, &v); u--,v--; g[u][v] = g[v][u] = -1; degree[u]++; degree[v]++; } for(int i=0; i<n; ++i){ g[i][i] = degree[i]; } printf("%lld\n", det(g, n)); } int main() { int t; scanf("%d", &t); while(t--){ solve(); } return 0; }
|
#
未解决的问题